@skillfm/local 2.7.2 → 2.7.4
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/checkup/daily-push.d.ts +29 -0
- package/dist/checkup/daily-push.d.ts.map +1 -0
- package/dist/checkup/daily-push.js +86 -0
- package/dist/checkup/daily-push.js.map +1 -0
- package/dist/checkup/dimension-1-usage.d.ts +22 -0
- package/dist/checkup/dimension-1-usage.d.ts.map +1 -0
- package/dist/checkup/dimension-1-usage.js +115 -0
- package/dist/checkup/dimension-1-usage.js.map +1 -0
- package/dist/checkup/dimension-3-files.d.ts +23 -0
- package/dist/checkup/dimension-3-files.d.ts.map +1 -0
- package/dist/checkup/dimension-3-files.js +165 -0
- package/dist/checkup/dimension-3-files.js.map +1 -0
- package/dist/checkup/dimension-4-context.d.ts +18 -0
- package/dist/checkup/dimension-4-context.d.ts.map +1 -0
- package/dist/checkup/dimension-4-context.js +177 -0
- package/dist/checkup/dimension-4-context.js.map +1 -0
- package/dist/checkup/index.d.ts +11 -0
- package/dist/checkup/index.d.ts.map +1 -0
- package/dist/checkup/index.js +10 -0
- package/dist/checkup/index.js.map +1 -0
- package/dist/checkup/report.d.ts +21 -0
- package/dist/checkup/report.d.ts.map +1 -0
- package/dist/checkup/report.js +133 -0
- package/dist/checkup/report.js.map +1 -0
- package/dist/checkup/score.d.ts +27 -0
- package/dist/checkup/score.d.ts.map +1 -0
- package/dist/checkup/score.js +101 -0
- package/dist/checkup/score.js.map +1 -0
- package/dist/checkup/types.d.ts +64 -0
- package/dist/checkup/types.d.ts.map +1 -0
- package/dist/checkup/types.js +5 -0
- package/dist/checkup/types.js.map +1 -0
- package/dist/connectors/anthropic.d.ts.map +1 -1
- package/dist/connectors/anthropic.js +3 -0
- package/dist/connectors/anthropic.js.map +1 -1
- package/dist/guard/bin.js +0 -0
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +27 -0
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/tools/checkup.d.ts +21 -0
- package/dist/mcp/tools/checkup.d.ts.map +1 -0
- package/dist/mcp/tools/checkup.js +35 -0
- package/dist/mcp/tools/checkup.js.map +1 -0
- package/dist/mcp/tools/explain-provider-key.d.ts.map +1 -1
- package/dist/mcp/tools/explain-provider-key.js +15 -13
- package/dist/mcp/tools/explain-provider-key.js.map +1 -1
- package/dist/mcp/tools/index.d.ts +6 -0
- package/dist/mcp/tools/index.d.ts.map +1 -1
- package/dist/mcp/tools/index.js +56 -4
- package/dist/mcp/tools/index.js.map +1 -1
- package/dist/mcp/tools/setup-gateway.d.ts +16 -0
- package/dist/mcp/tools/setup-gateway.d.ts.map +1 -0
- package/dist/mcp/tools/setup-gateway.js +79 -0
- package/dist/mcp/tools/setup-gateway.js.map +1 -0
- package/dist/mcp/tools/show-my-usage.d.ts +26 -0
- package/dist/mcp/tools/show-my-usage.d.ts.map +1 -0
- package/dist/mcp/tools/show-my-usage.js +68 -0
- package/dist/mcp/tools/show-my-usage.js.map +1 -0
- package/dist/mcp-stdio/bin.js +0 -0
- package/dist/reconciliation/engine.d.ts +30 -0
- package/dist/reconciliation/engine.d.ts.map +1 -0
- package/dist/reconciliation/engine.js +62 -0
- package/dist/reconciliation/engine.js.map +1 -0
- package/dist/reconciliation/index.d.ts +8 -0
- package/dist/reconciliation/index.d.ts.map +1 -0
- package/dist/reconciliation/index.js +8 -0
- package/dist/reconciliation/index.js.map +1 -0
- package/dist/reconciliation/l1-reconciler.d.ts +29 -0
- package/dist/reconciliation/l1-reconciler.d.ts.map +1 -0
- package/dist/reconciliation/l1-reconciler.js +144 -0
- package/dist/reconciliation/l1-reconciler.js.map +1 -0
- package/dist/reconciliation/l2-reconciler.d.ts +21 -0
- package/dist/reconciliation/l2-reconciler.d.ts.map +1 -0
- package/dist/reconciliation/l2-reconciler.js +241 -0
- package/dist/reconciliation/l2-reconciler.js.map +1 -0
- package/dist/reconciliation/types.d.ts +49 -0
- package/dist/reconciliation/types.d.ts.map +1 -0
- package/dist/reconciliation/types.js +9 -0
- package/dist/reconciliation/types.js.map +1 -0
- package/dist/save-token/e1-router.d.ts +7 -0
- package/dist/save-token/e1-router.d.ts.map +1 -0
- package/dist/save-token/e1-router.js +112 -0
- package/dist/save-token/e1-router.js.map +1 -0
- package/dist/save-token/e2-cache.d.ts +7 -0
- package/dist/save-token/e2-cache.d.ts.map +1 -0
- package/dist/save-token/e2-cache.js +128 -0
- package/dist/save-token/e2-cache.js.map +1 -0
- package/dist/save-token/e3-batch.d.ts +7 -0
- package/dist/save-token/e3-batch.d.ts.map +1 -0
- package/dist/save-token/e3-batch.js +80 -0
- package/dist/save-token/e3-batch.js.map +1 -0
- package/dist/save-token/gateway-setup.d.ts +27 -0
- package/dist/save-token/gateway-setup.d.ts.map +1 -0
- package/dist/save-token/gateway-setup.js +200 -0
- package/dist/save-token/gateway-setup.js.map +1 -0
- package/dist/save-token/index.d.ts +13 -0
- package/dist/save-token/index.d.ts.map +1 -0
- package/dist/save-token/index.js +23 -0
- package/dist/save-token/index.js.map +1 -0
- package/dist/save-token/types.d.ts +46 -0
- package/dist/save-token/types.d.ts.map +1 -0
- package/dist/save-token/types.js +5 -0
- package/dist/save-token/types.js.map +1 -0
- package/dist/usage-local/index.d.ts +32 -0
- package/dist/usage-local/index.d.ts.map +1 -0
- package/dist/usage-local/index.js +32 -0
- package/dist/usage-local/index.js.map +1 -0
- package/dist/usage-local/model-pricing.d.ts +38 -0
- package/dist/usage-local/model-pricing.d.ts.map +1 -0
- package/dist/usage-local/model-pricing.js +230 -0
- package/dist/usage-local/model-pricing.js.map +1 -0
- package/dist/usage-local/openclaw-watcher.d.ts +35 -0
- package/dist/usage-local/openclaw-watcher.d.ts.map +1 -0
- package/dist/usage-local/openclaw-watcher.js +190 -0
- package/dist/usage-local/openclaw-watcher.js.map +1 -0
- package/dist/usage-local/store.d.ts +50 -0
- package/dist/usage-local/store.d.ts.map +1 -0
- package/dist/usage-local/store.js +201 -0
- package/dist/usage-local/store.js.map +1 -0
- package/dist/usage-local/types.d.ts +94 -0
- package/dist/usage-local/types.d.ts.map +1 -0
- package/dist/usage-local/types.js +6 -0
- package/dist/usage-local/types.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
// sdk/skillfm-local/src/checkup/dimension-4-context.ts
|
|
2
|
+
//
|
|
3
|
+
// 维度 4: 上下文占用 / 一键整理 (PRD §4.4) — AI 时代独有.
|
|
4
|
+
// 检测各 agent harness 的当前 session 上下文 % 用量.
|
|
5
|
+
//
|
|
6
|
+
// MVP: 只 surface OpenClaw (我们已 verify 真 schema), Claude Code/Cursor 后续 batch.
|
|
7
|
+
import * as fs from 'node:fs';
|
|
8
|
+
import * as path from 'node:path';
|
|
9
|
+
import { homedir } from 'node:os';
|
|
10
|
+
const OPENCLAW_AGENTS_DIR = path.join(homedir(), '.openclaw', 'agents');
|
|
11
|
+
/**
|
|
12
|
+
* 估算 model 的 context window 上限 (粗略, MVP)
|
|
13
|
+
* 后续可改成跟 model-pricing.ts 联动 (按 modelId 真查上限)
|
|
14
|
+
*/
|
|
15
|
+
function estimateContextWindow(modelId) {
|
|
16
|
+
const m = modelId.toLowerCase();
|
|
17
|
+
if (m.includes('claude') && m.includes('1m'))
|
|
18
|
+
return 1_000_000;
|
|
19
|
+
if (m.includes('claude'))
|
|
20
|
+
return 200_000;
|
|
21
|
+
if (m.includes('gpt-4o') || m.includes('o1'))
|
|
22
|
+
return 128_000;
|
|
23
|
+
if (m.includes('gpt-4-turbo'))
|
|
24
|
+
return 128_000;
|
|
25
|
+
if (m.includes('minimax'))
|
|
26
|
+
return 200_000;
|
|
27
|
+
if (m.includes('deepseek'))
|
|
28
|
+
return 128_000;
|
|
29
|
+
if (m.includes('qwen'))
|
|
30
|
+
return 128_000;
|
|
31
|
+
if (m.includes('doubao'))
|
|
32
|
+
return 128_000;
|
|
33
|
+
if (m.includes('kimi'))
|
|
34
|
+
return 200_000;
|
|
35
|
+
return 128_000; // fallback
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* 扫 OpenClaw agents/<id>/sessions/*.trajectory.jsonl 的最后一条 model.completed
|
|
39
|
+
* 看当前 session 累计 token + 估算 context window 占用
|
|
40
|
+
*/
|
|
41
|
+
async function scanOpenClawSessions() {
|
|
42
|
+
if (!fs.existsSync(OPENCLAW_AGENTS_DIR))
|
|
43
|
+
return [];
|
|
44
|
+
const out = [];
|
|
45
|
+
const agents = await fs.promises.readdir(OPENCLAW_AGENTS_DIR, { withFileTypes: true });
|
|
46
|
+
for (const agent of agents) {
|
|
47
|
+
if (!agent.isDirectory())
|
|
48
|
+
continue;
|
|
49
|
+
const sessionsDir = path.join(OPENCLAW_AGENTS_DIR, agent.name, 'sessions');
|
|
50
|
+
if (!fs.existsSync(sessionsDir))
|
|
51
|
+
continue;
|
|
52
|
+
const files = await fs.promises.readdir(sessionsDir);
|
|
53
|
+
for (const f of files) {
|
|
54
|
+
if (!f.endsWith('.trajectory.jsonl'))
|
|
55
|
+
continue;
|
|
56
|
+
const filePath = path.join(sessionsDir, f);
|
|
57
|
+
const status = await readLastModelCompleted(filePath);
|
|
58
|
+
if (status)
|
|
59
|
+
out.push(status);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return out;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* 读 trajectory.jsonl 最后一个 model.completed event
|
|
66
|
+
* 返 ContextStatus (含 input/output/cacheRead 加总作为当前 context size 估算)
|
|
67
|
+
*/
|
|
68
|
+
async function readLastModelCompleted(filePath) {
|
|
69
|
+
try {
|
|
70
|
+
// tail 100KB (大多数 jsonl session 是 5-10MB, 后 100KB 足够找最近 event)
|
|
71
|
+
const stat = await fs.promises.stat(filePath);
|
|
72
|
+
const readSize = Math.min(stat.size, 100 * 1024);
|
|
73
|
+
const startOffset = stat.size - readSize;
|
|
74
|
+
const buf = Buffer.alloc(readSize);
|
|
75
|
+
const fd = await fs.promises.open(filePath, 'r');
|
|
76
|
+
try {
|
|
77
|
+
await fd.read(buf, 0, readSize, startOffset);
|
|
78
|
+
}
|
|
79
|
+
finally {
|
|
80
|
+
await fd.close();
|
|
81
|
+
}
|
|
82
|
+
const text = buf.toString('utf-8');
|
|
83
|
+
const lines = text.split('\n').reverse();
|
|
84
|
+
let modelId = '';
|
|
85
|
+
let provider = '';
|
|
86
|
+
let lastUsage = null;
|
|
87
|
+
let turn_count = 0;
|
|
88
|
+
for (const line of lines) {
|
|
89
|
+
if (!line.trim().startsWith('{'))
|
|
90
|
+
continue;
|
|
91
|
+
try {
|
|
92
|
+
const ev = JSON.parse(line);
|
|
93
|
+
if (ev.type === 'model.completed' && ev.data?.usage) {
|
|
94
|
+
turn_count += 1;
|
|
95
|
+
if (!lastUsage) {
|
|
96
|
+
lastUsage = ev.data.usage;
|
|
97
|
+
modelId = ev.modelId ?? '';
|
|
98
|
+
provider = ev.provider ?? '';
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
// skip
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if (!lastUsage)
|
|
107
|
+
return null;
|
|
108
|
+
// 当前 context size ~ input + cacheRead (system prompt + history)
|
|
109
|
+
const current_tokens = (lastUsage.input ?? 0) + (lastUsage.cacheRead ?? 0);
|
|
110
|
+
const max = estimateContextWindow(modelId);
|
|
111
|
+
return {
|
|
112
|
+
agent_harness: 'openclaw',
|
|
113
|
+
session_id: path.basename(filePath, '.trajectory.jsonl'),
|
|
114
|
+
current_tokens,
|
|
115
|
+
context_window_max: max,
|
|
116
|
+
utilization_pct: (current_tokens / max) * 100,
|
|
117
|
+
turn_count,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
export async function checkDimensionContext() {
|
|
125
|
+
const sessions = await scanOpenClawSessions();
|
|
126
|
+
const findings = [];
|
|
127
|
+
let severity = 'healthy';
|
|
128
|
+
// 找最严重的 session (占比最高)
|
|
129
|
+
const sorted = sessions.sort((a, b) => b.utilization_pct - a.utilization_pct);
|
|
130
|
+
const worst = sorted[0];
|
|
131
|
+
if (worst) {
|
|
132
|
+
if (worst.utilization_pct > 90) {
|
|
133
|
+
findings.push({
|
|
134
|
+
headline: `${worst.agent_harness} session 上下文 ${worst.utilization_pct.toFixed(0)}% — 接近爆`,
|
|
135
|
+
severity: 'critical',
|
|
136
|
+
score_deduction: 25,
|
|
137
|
+
fix_label: 'rotate session (新干净 session, 旧 turn summary 进 memory) [Pro 自动]',
|
|
138
|
+
fix_free_allowed: false, // Free 只 surface 提示, Pro 自动 rotate
|
|
139
|
+
estimated_savings: { description: '估省后续 60% input token' },
|
|
140
|
+
});
|
|
141
|
+
severity = 'critical';
|
|
142
|
+
}
|
|
143
|
+
else if (worst.utilization_pct > 80) {
|
|
144
|
+
findings.push({
|
|
145
|
+
headline: `${worst.agent_harness} session 上下文 ${worst.utilization_pct.toFixed(0)}% — 偏高`,
|
|
146
|
+
severity: 'warning',
|
|
147
|
+
score_deduction: 15,
|
|
148
|
+
fix_label: 'rotate session 让 agent 又快又聪明 [Pro 自动]',
|
|
149
|
+
fix_free_allowed: false,
|
|
150
|
+
estimated_savings: { description: '估省后续 40% input token' },
|
|
151
|
+
});
|
|
152
|
+
severity = 'warning';
|
|
153
|
+
}
|
|
154
|
+
else if (worst.turn_count > 30) {
|
|
155
|
+
findings.push({
|
|
156
|
+
headline: `${worst.agent_harness} session 已 ${worst.turn_count} turn — 建议考虑 rotate`,
|
|
157
|
+
severity: 'info',
|
|
158
|
+
score_deduction: 5,
|
|
159
|
+
fix_label: '考虑新开 session [Pro 自动]',
|
|
160
|
+
fix_free_allowed: false,
|
|
161
|
+
});
|
|
162
|
+
severity = 'info';
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
const headline = worst
|
|
166
|
+
? `${worst.agent_harness} ${worst.utilization_pct.toFixed(0)}%${sessions.length > 1 ? ` (${sessions.length} session)` : ''}`
|
|
167
|
+
: '无 active session';
|
|
168
|
+
return {
|
|
169
|
+
dimension: 'context',
|
|
170
|
+
severity,
|
|
171
|
+
headline,
|
|
172
|
+
findings,
|
|
173
|
+
pro_locked: false,
|
|
174
|
+
sessions,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
//# sourceMappingURL=dimension-4-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dimension-4-context.js","sourceRoot":"","sources":["../../src/checkup/dimension-4-context.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type { DimensionId, Severity, Finding, DimensionStatus, CheckupReport, HealthSnapshot, } from './types.js';
|
|
2
|
+
export { runCheckup, renderMainEntry } from './report.js';
|
|
3
|
+
export type { CheckupDeps } from './report.js';
|
|
4
|
+
export { computeHealthScore, selectTopFocus, computeTrend, loadHealthHistory, appendHealthSnapshot, } from './score.js';
|
|
5
|
+
export { checkDimensionUsage, buildUsageSurfaceLines } from './dimension-1-usage.js';
|
|
6
|
+
export type { UsageDimDeps } from './dimension-1-usage.js';
|
|
7
|
+
export { checkDimensionFiles, executeFileCleanup } from './dimension-3-files.js';
|
|
8
|
+
export { checkDimensionContext } from './dimension-4-context.js';
|
|
9
|
+
export { renderDailyPush, renderAnomalyPush, shouldPushRealtimeAnomaly, pushTimeToCron, DEFAULT_PUSH_CONFIG, } from './daily-push.js';
|
|
10
|
+
export type { DailyPushConfig, PushTime } from './daily-push.js';
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/checkup/index.ts"],"names":[],"mappings":"AAIA,YAAY,EACV,WAAW,EACX,QAAQ,EACR,OAAO,EACP,eAAe,EACf,aAAa,EACb,cAAc,GACf,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC1D,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,YAAY,EACZ,iBAAiB,EACjB,oBAAoB,GACrB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AACrF,YAAY,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AACjF,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,yBAAyB,EACzB,cAAc,EACd,mBAAmB,GACpB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// sdk/skillfm-local/src/checkup/index.ts
|
|
2
|
+
//
|
|
3
|
+
// Checkup public API.
|
|
4
|
+
export { runCheckup, renderMainEntry } from './report.js';
|
|
5
|
+
export { computeHealthScore, selectTopFocus, computeTrend, loadHealthHistory, appendHealthSnapshot, } from './score.js';
|
|
6
|
+
export { checkDimensionUsage, buildUsageSurfaceLines } from './dimension-1-usage.js';
|
|
7
|
+
export { checkDimensionFiles, executeFileCleanup } from './dimension-3-files.js';
|
|
8
|
+
export { checkDimensionContext } from './dimension-4-context.js';
|
|
9
|
+
export { renderDailyPush, renderAnomalyPush, shouldPushRealtimeAnomaly, pushTimeToCron, DEFAULT_PUSH_CONFIG, } from './daily-push.js';
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/checkup/index.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,EAAE;AACF,sBAAsB;AAUtB,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE1D,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,YAAY,EACZ,iBAAiB,EACjB,oBAAoB,GACrB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAErF,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AACjF,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,yBAAyB,EACzB,cAAc,EACd,mBAAmB,GACpB,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { LocalUsageStore } from '../usage-local/store.js';
|
|
2
|
+
import type { ReconciliationEngine } from '../reconciliation/index.js';
|
|
3
|
+
import type { CheckupReport } from './types.js';
|
|
4
|
+
export interface CheckupDeps {
|
|
5
|
+
store: LocalUsageStore;
|
|
6
|
+
reconciliationEngine: ReconciliationEngine;
|
|
7
|
+
/** 是否为 Pro 用户 (锁标控制) */
|
|
8
|
+
is_pro: boolean;
|
|
9
|
+
/** 跳过 history 写入 (测试用) */
|
|
10
|
+
skip_persist?: boolean;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* 主入口 — 跑一次全 5 维度体检 → CheckupReport
|
|
14
|
+
*/
|
|
15
|
+
export declare function runCheckup(deps: CheckupDeps): Promise<CheckupReport>;
|
|
16
|
+
/**
|
|
17
|
+
* 主入口 UX 渲染 — 把 CheckupReport 渲染成 < 300 字的中文文本块
|
|
18
|
+
* (PRD §3.1 极简主入口)
|
|
19
|
+
*/
|
|
20
|
+
export declare function renderMainEntry(report: CheckupReport): string;
|
|
21
|
+
//# sourceMappingURL=report.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../src/checkup/report.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAEvE,OAAO,KAAK,EAAE,aAAa,EAAmB,MAAM,YAAY,CAAC;AAWjE,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,eAAe,CAAC;IACvB,oBAAoB,EAAE,oBAAoB,CAAC;IAC3C,wBAAwB;IACxB,MAAM,EAAE,OAAO,CAAC;IAChB,0BAA0B;IAC1B,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;GAEG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,aAAa,CAAC,CAgE1E;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,CAgD7D"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
// sdk/skillfm-local/src/checkup/report.ts
|
|
2
|
+
//
|
|
3
|
+
// CheckupReport 拼装 — 主入口数据源.
|
|
4
|
+
// runCheckup() 跑全体 5 维度 + 算 score + 选 top focus + 持久化 history.
|
|
5
|
+
import { checkDimensionUsage, buildUsageSurfaceLines } from './dimension-1-usage.js';
|
|
6
|
+
import { checkDimensionFiles } from './dimension-3-files.js';
|
|
7
|
+
import { checkDimensionContext } from './dimension-4-context.js';
|
|
8
|
+
import { computeHealthScore, selectTopFocus, computeTrend, appendHealthSnapshot, } from './score.js';
|
|
9
|
+
/**
|
|
10
|
+
* 主入口 — 跑一次全 5 维度体检 → CheckupReport
|
|
11
|
+
*/
|
|
12
|
+
export async function runCheckup(deps) {
|
|
13
|
+
const generated_at = new Date().toISOString();
|
|
14
|
+
// 维度 1: 用量 (含 reconciliation)
|
|
15
|
+
const reconciliations = await deps.reconciliationEngine.reconcileAll();
|
|
16
|
+
const usage = checkDimensionUsage({
|
|
17
|
+
store: deps.store,
|
|
18
|
+
reconciliations,
|
|
19
|
+
});
|
|
20
|
+
// 维度 3: 文件 (并行扫)
|
|
21
|
+
const files = await checkDimensionFiles();
|
|
22
|
+
// 维度 4: 上下文
|
|
23
|
+
const context = await checkDimensionContext();
|
|
24
|
+
// 维度 2: 技术债 (Pro 锁, MVP 不做)
|
|
25
|
+
const tech_debt = {
|
|
26
|
+
dimension: 'tech_debt',
|
|
27
|
+
severity: 'pro_locked',
|
|
28
|
+
headline: deps.is_pro ? '即将上线 (2.7.5)' : 'Pro 解锁',
|
|
29
|
+
findings: [],
|
|
30
|
+
pro_locked: !deps.is_pro,
|
|
31
|
+
};
|
|
32
|
+
// 维度 5: 记忆 (Pro 锁, MVP 不做)
|
|
33
|
+
const memory = {
|
|
34
|
+
dimension: 'memory',
|
|
35
|
+
severity: 'pro_locked',
|
|
36
|
+
headline: deps.is_pro ? '即将上线 (2.7.6)' : 'Pro 解锁',
|
|
37
|
+
findings: [],
|
|
38
|
+
pro_locked: !deps.is_pro,
|
|
39
|
+
};
|
|
40
|
+
const dimensions = [usage, files, context, tech_debt, memory];
|
|
41
|
+
const health_score = computeHealthScore(dimensions);
|
|
42
|
+
const health_trend = await computeTrend(health_score).catch(() => undefined);
|
|
43
|
+
const top_focus = selectTopFocus(dimensions);
|
|
44
|
+
const usage_summary_lines = buildUsageSurfaceLines(reconciliations);
|
|
45
|
+
const all_healthy = dimensions.every((d) => d.severity === 'healthy' || d.severity === 'pro_locked' || d.severity === 'no_data');
|
|
46
|
+
const report = {
|
|
47
|
+
generated_at,
|
|
48
|
+
health_score,
|
|
49
|
+
health_trend,
|
|
50
|
+
dimensions,
|
|
51
|
+
top_focus,
|
|
52
|
+
usage_summary_lines,
|
|
53
|
+
all_healthy,
|
|
54
|
+
};
|
|
55
|
+
// 持久化 health snapshot (用于下次 trend)
|
|
56
|
+
if (!deps.skip_persist) {
|
|
57
|
+
await appendHealthSnapshot({ timestamp: generated_at, health_score }).catch(() => {
|
|
58
|
+
// 写失败不阻塞 report
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
return report;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* 主入口 UX 渲染 — 把 CheckupReport 渲染成 < 300 字的中文文本块
|
|
65
|
+
* (PRD §3.1 极简主入口)
|
|
66
|
+
*/
|
|
67
|
+
export function renderMainEntry(report) {
|
|
68
|
+
const lines = [];
|
|
69
|
+
const trendStr = report.health_trend != null
|
|
70
|
+
? (report.health_trend > 0 ? ` (上次 ${report.health_score - report.health_trend}, ↑${report.health_trend})` : ` (上次 ${report.health_score - report.health_trend}, ↓${-report.health_trend})`)
|
|
71
|
+
: '';
|
|
72
|
+
const overall_emoji = report.health_score >= 90 ? '✨' : report.health_score >= 70 ? '✅' : report.health_score >= 50 ? '⚠️' : '🔴';
|
|
73
|
+
lines.push(`🧬 你家 AI · 健康度 ${report.health_score}/100 ${overall_emoji}${trendStr}`);
|
|
74
|
+
lines.push('━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
75
|
+
lines.push('');
|
|
76
|
+
// 维度行
|
|
77
|
+
for (const dim of report.dimensions) {
|
|
78
|
+
const sevEmoji = severityEmoji(dim.severity);
|
|
79
|
+
const lockTag = dim.pro_locked ? ' [Pro 解锁]' : '';
|
|
80
|
+
const dimLabel = labelOf(dim.dimension);
|
|
81
|
+
lines.push(`${dimLabel}${sevEmoji} ${dim.headline}${lockTag}`);
|
|
82
|
+
}
|
|
83
|
+
// 用量子行 (对账 surface, 主入口灵魂位置)
|
|
84
|
+
if (report.usage_summary_lines.length > 0) {
|
|
85
|
+
lines.push('');
|
|
86
|
+
for (const sl of report.usage_summary_lines) {
|
|
87
|
+
lines.push(` ${sl}`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// Today's #1
|
|
91
|
+
lines.push('');
|
|
92
|
+
lines.push('━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
93
|
+
if (report.all_healthy) {
|
|
94
|
+
lines.push(`✨ 今日: 你家 AI 高效如初. 保持!`);
|
|
95
|
+
}
|
|
96
|
+
else if (report.top_focus) {
|
|
97
|
+
lines.push(`今日 #1: ${report.top_focus.headline}`);
|
|
98
|
+
if (report.top_focus.fix_label) {
|
|
99
|
+
lines.push(` ${report.top_focus.fix_label}`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
// Action buttons
|
|
103
|
+
lines.push('');
|
|
104
|
+
if (report.top_focus?.fix_free_allowed) {
|
|
105
|
+
lines.push('[🛠 修这一个] [📊 看全部] [⏰ 设每日] [✨ Pro]');
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
lines.push('[📊 看全部] [⏰ 设每日] [✨ Pro 解锁自动 fix]');
|
|
109
|
+
}
|
|
110
|
+
return lines.join('\n');
|
|
111
|
+
}
|
|
112
|
+
function severityEmoji(s) {
|
|
113
|
+
switch (s) {
|
|
114
|
+
case 'critical': return ' 🔴';
|
|
115
|
+
case 'warning': return ' 🟠';
|
|
116
|
+
case 'info': return ' 🟡';
|
|
117
|
+
case 'healthy': return ' ✅';
|
|
118
|
+
case 'pro_locked': return '';
|
|
119
|
+
case 'no_data': return ' ❓';
|
|
120
|
+
default: return '';
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
function labelOf(dim) {
|
|
124
|
+
switch (dim) {
|
|
125
|
+
case 'usage': return '💰 用量 ';
|
|
126
|
+
case 'tech_debt': return '🐛 技术债 ';
|
|
127
|
+
case 'files': return '📦 文件 ';
|
|
128
|
+
case 'context': return '📁 上下文 ';
|
|
129
|
+
case 'memory': return '🧠 记忆 ';
|
|
130
|
+
default: return dim;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=report.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report.js","sourceRoot":"","sources":["../../src/checkup/report.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { DimensionStatus, Finding, HealthSnapshot } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* 算总 score (基于所有 dimension 的 findings)
|
|
4
|
+
*/
|
|
5
|
+
export declare function computeHealthScore(dimensions: DimensionStatus[]): number;
|
|
6
|
+
/**
|
|
7
|
+
* 选 "今日 #1" — 最该 surface 的 1 个 finding (PRD §3.2 治信息过载)
|
|
8
|
+
*
|
|
9
|
+
* 选择策略 (按优先级):
|
|
10
|
+
* 1. 最严重 critical (score_deduction 最高)
|
|
11
|
+
* 2. 如果有 fix_free_allowed=true 的 critical, 优先选可执行的 (用户能立刻动作)
|
|
12
|
+
* 3. 否则取所有 findings 中 score_deduction 最高的
|
|
13
|
+
*/
|
|
14
|
+
export declare function selectTopFocus(dimensions: DimensionStatus[]): Finding | null;
|
|
15
|
+
/**
|
|
16
|
+
* 加载健康度历史 (用于 trend 计算)
|
|
17
|
+
*/
|
|
18
|
+
export declare function loadHealthHistory(filePath?: string): Promise<HealthSnapshot[]>;
|
|
19
|
+
/**
|
|
20
|
+
* Append 一条健康度 snapshot
|
|
21
|
+
*/
|
|
22
|
+
export declare function appendHealthSnapshot(snap: HealthSnapshot, filePath?: string): Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* 算 trend (vs 上次 snapshot)
|
|
25
|
+
*/
|
|
26
|
+
export declare function computeTrend(currentScore: number, historyPath?: string): Promise<number | undefined>;
|
|
27
|
+
//# sourceMappingURL=score.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"score.d.ts","sourceRoot":"","sources":["../../src/checkup/score.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAiB,eAAe,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAI1F;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,eAAe,EAAE,GAAG,MAAM,CASxE;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,eAAe,EAAE,GAAG,OAAO,GAAG,IAAI,CAwB5E;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,QAAQ,GAAE,MAA4B,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAczG;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,cAAc,EACpB,QAAQ,GAAE,MAA4B,GACrC,OAAO,CAAC,IAAI,CAAC,CAMf;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,YAAY,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAK1G"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
// sdk/skillfm-local/src/checkup/score.ts
|
|
2
|
+
//
|
|
3
|
+
// 健康度公式 (PRD V1.3 §7, Eric 拍板):
|
|
4
|
+
// 用量 40% / 上下文 25% / 文件 15% / 技术债 10% / 记忆 10%
|
|
5
|
+
//
|
|
6
|
+
// 算法: score = max(0, 100 - Σ (weight × dimension_deduction_normalized))
|
|
7
|
+
// 但因 finding 有 score_deduction 真值, 简化为:
|
|
8
|
+
// score = max(0, 100 - Σ findings[].score_deduction)
|
|
9
|
+
//
|
|
10
|
+
// Free 用户: 上限 100 (Eric 决策 #6, 不区分不 cripple)
|
|
11
|
+
// Pro 维度 (技术债/记忆) 在 Free 用户的 deduction = 0 (锁了不算分)
|
|
12
|
+
import * as fs from 'node:fs';
|
|
13
|
+
import * as path from 'node:path';
|
|
14
|
+
import { homedir } from 'node:os';
|
|
15
|
+
const HEALTH_HISTORY_PATH = path.join(homedir(), '.skillfm', 'health-history.jsonl');
|
|
16
|
+
/**
|
|
17
|
+
* 算总 score (基于所有 dimension 的 findings)
|
|
18
|
+
*/
|
|
19
|
+
export function computeHealthScore(dimensions) {
|
|
20
|
+
let totalDeduction = 0;
|
|
21
|
+
for (const dim of dimensions) {
|
|
22
|
+
if (dim.pro_locked)
|
|
23
|
+
continue; // Free 用户 Pro 维度不算分
|
|
24
|
+
for (const finding of dim.findings) {
|
|
25
|
+
totalDeduction += finding.score_deduction;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return Math.max(0, Math.min(100, 100 - totalDeduction));
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* 选 "今日 #1" — 最该 surface 的 1 个 finding (PRD §3.2 治信息过载)
|
|
32
|
+
*
|
|
33
|
+
* 选择策略 (按优先级):
|
|
34
|
+
* 1. 最严重 critical (score_deduction 最高)
|
|
35
|
+
* 2. 如果有 fix_free_allowed=true 的 critical, 优先选可执行的 (用户能立刻动作)
|
|
36
|
+
* 3. 否则取所有 findings 中 score_deduction 最高的
|
|
37
|
+
*/
|
|
38
|
+
export function selectTopFocus(dimensions) {
|
|
39
|
+
const allFindings = [];
|
|
40
|
+
for (const dim of dimensions) {
|
|
41
|
+
if (dim.pro_locked)
|
|
42
|
+
continue;
|
|
43
|
+
allFindings.push(...dim.findings);
|
|
44
|
+
}
|
|
45
|
+
if (allFindings.length === 0)
|
|
46
|
+
return null;
|
|
47
|
+
// 优先 critical + fix_free_allowed
|
|
48
|
+
const critFreeFix = allFindings.filter((f) => f.severity === 'critical' && f.fix_free_allowed);
|
|
49
|
+
if (critFreeFix.length > 0) {
|
|
50
|
+
return critFreeFix.sort((a, b) => b.score_deduction - a.score_deduction)[0];
|
|
51
|
+
}
|
|
52
|
+
// 其次 critical
|
|
53
|
+
const crit = allFindings.filter((f) => f.severity === 'critical');
|
|
54
|
+
if (crit.length > 0) {
|
|
55
|
+
return crit.sort((a, b) => b.score_deduction - a.score_deduction)[0];
|
|
56
|
+
}
|
|
57
|
+
// 最后按 deduction 排序
|
|
58
|
+
return allFindings.sort((a, b) => b.score_deduction - a.score_deduction)[0];
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* 加载健康度历史 (用于 trend 计算)
|
|
62
|
+
*/
|
|
63
|
+
export async function loadHealthHistory(filePath = HEALTH_HISTORY_PATH) {
|
|
64
|
+
if (!fs.existsSync(filePath))
|
|
65
|
+
return [];
|
|
66
|
+
const text = await fs.promises.readFile(filePath, 'utf-8');
|
|
67
|
+
const out = [];
|
|
68
|
+
for (const line of text.split('\n')) {
|
|
69
|
+
const t = line.trim();
|
|
70
|
+
if (!t.startsWith('{'))
|
|
71
|
+
continue;
|
|
72
|
+
try {
|
|
73
|
+
out.push(JSON.parse(t));
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
// skip
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return out.sort((a, b) => a.timestamp.localeCompare(b.timestamp));
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Append 一条健康度 snapshot
|
|
83
|
+
*/
|
|
84
|
+
export async function appendHealthSnapshot(snap, filePath = HEALTH_HISTORY_PATH) {
|
|
85
|
+
const dir = path.dirname(filePath);
|
|
86
|
+
if (!fs.existsSync(dir)) {
|
|
87
|
+
await fs.promises.mkdir(dir, { recursive: true, mode: 0o700 });
|
|
88
|
+
}
|
|
89
|
+
await fs.promises.appendFile(filePath, JSON.stringify(snap) + '\n', { mode: 0o600 });
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* 算 trend (vs 上次 snapshot)
|
|
93
|
+
*/
|
|
94
|
+
export async function computeTrend(currentScore, historyPath) {
|
|
95
|
+
const history = await loadHealthHistory(historyPath);
|
|
96
|
+
if (history.length === 0)
|
|
97
|
+
return undefined;
|
|
98
|
+
const last = history[history.length - 1];
|
|
99
|
+
return currentScore - last.health_score;
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=score.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"score.js","sourceRoot":"","sources":["../../src/checkup/score.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
export type DimensionId = 'usage' | 'tech_debt' | 'files' | 'context' | 'memory';
|
|
2
|
+
export type Severity = 'critical' | 'warning' | 'info' | 'healthy' | 'pro_locked' | 'no_data';
|
|
3
|
+
/**
|
|
4
|
+
* 一个 deduction = 一项发现的问题 (用于 score 计算 + UX surface)
|
|
5
|
+
*/
|
|
6
|
+
export interface Finding {
|
|
7
|
+
/** 短描述 (主入口 surface 行用) */
|
|
8
|
+
headline: string;
|
|
9
|
+
/** 严重度 */
|
|
10
|
+
severity: Severity;
|
|
11
|
+
/** 扣分 (0-30) */
|
|
12
|
+
score_deduction: number;
|
|
13
|
+
/** 一键 fix 文案 (可选, 主入口 [修这一个] 时用) */
|
|
14
|
+
fix_label?: string;
|
|
15
|
+
/** 是否 Free 用户可执行 fix */
|
|
16
|
+
fix_free_allowed?: boolean;
|
|
17
|
+
/** 真省 (如果 fix 后, 估算月省 token / ¥) */
|
|
18
|
+
estimated_savings?: {
|
|
19
|
+
tokens?: number;
|
|
20
|
+
cny?: number;
|
|
21
|
+
description?: string;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* 单个维度的体检结果
|
|
26
|
+
*/
|
|
27
|
+
export interface DimensionStatus {
|
|
28
|
+
dimension: DimensionId;
|
|
29
|
+
/** 维度总 severity (取 findings 中最高) */
|
|
30
|
+
severity: Severity;
|
|
31
|
+
/** 维度 1 行 headline (主入口 surface) */
|
|
32
|
+
headline: string;
|
|
33
|
+
/** 该维度所有 findings */
|
|
34
|
+
findings: Finding[];
|
|
35
|
+
/** Pro 锁标 */
|
|
36
|
+
pro_locked: boolean;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Checkup 完整报告 — 主入口数据源
|
|
40
|
+
*/
|
|
41
|
+
export interface CheckupReport {
|
|
42
|
+
generated_at: string;
|
|
43
|
+
/** 整体健康度 0-100 */
|
|
44
|
+
health_score: number;
|
|
45
|
+
/** vs 上次 score 的变化 (+/- 数, 用于 trend "↑ 28") */
|
|
46
|
+
health_trend?: number;
|
|
47
|
+
/** 5 维度状态 */
|
|
48
|
+
dimensions: DimensionStatus[];
|
|
49
|
+
/** "今日 #1" — 最该看的 1 件事 (treats 信息过载, PRD §3.2) */
|
|
50
|
+
top_focus: Finding | null;
|
|
51
|
+
/** 主入口的"💰 用量"那一行 (来自 reconciliation summary) */
|
|
52
|
+
usage_summary_lines: string[];
|
|
53
|
+
/** 是否所有维度都 healthy → fallback UX */
|
|
54
|
+
all_healthy: boolean;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* 健康度历史 snapshot (持久化在 ~/.skillfm/health-history.jsonl)
|
|
58
|
+
* 用于 trend 计算 + Daily push 文案
|
|
59
|
+
*/
|
|
60
|
+
export interface HealthSnapshot {
|
|
61
|
+
timestamp: string;
|
|
62
|
+
health_score: number;
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/checkup/types.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,WAAW,GACnB,OAAO,GACP,WAAW,GACX,OAAO,GACP,SAAS,GACT,QAAQ,CAAC;AAEb,MAAM,MAAM,QAAQ,GAChB,UAAU,GACV,SAAS,GACT,MAAM,GACN,SAAS,GACT,YAAY,GACZ,SAAS,CAAC;AAEd;;GAEG;AACH,MAAM,WAAW,OAAO;IACtB,2BAA2B;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU;IACV,QAAQ,EAAE,QAAQ,CAAC;IACnB,gBAAgB;IAChB,eAAe,EAAE,MAAM,CAAC;IACxB,oCAAoC;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wBAAwB;IACxB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,oCAAoC;IACpC,iBAAiB,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7E;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,WAAW,CAAC;IACvB,oCAAoC;IACpC,QAAQ,EAAE,QAAQ,CAAC;IACnB,oCAAoC;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,qBAAqB;IACrB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,aAAa;IACb,UAAU,EAAE,OAAO,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,kBAAkB;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,+CAA+C;IAC/C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa;IACb,UAAU,EAAE,eAAe,EAAE,CAAC;IAC9B,kDAAkD;IAClD,SAAS,EAAE,OAAO,GAAG,IAAI,CAAC;IAC1B,iDAAiD;IACjD,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,oCAAoC;IACpC,WAAW,EAAE,OAAO,CAAC;CACtB;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;CACtB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/checkup/types.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,EAAE;AACF,qDAAqD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["../../src/connectors/anthropic.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAuC1F,qBAAa,kBAAmB,SAAQ,aAAa;IACnD,EAAE,EAAE,WAAW,CAAe;IAC9B,IAAI,SAAsB;IAC1B,OAAO,UAAQ;IAET,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["../../src/connectors/anthropic.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAuC1F,qBAAa,kBAAmB,SAAQ,aAAa;IACnD,EAAE,EAAE,WAAW,CAAe;IAC9B,IAAI,SAAsB;IAC1B,OAAO,UAAQ;IAET,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAqD7E,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;CA8BlD"}
|
|
@@ -30,12 +30,15 @@ export class AnthropicConnector extends BaseConnector {
|
|
|
30
30
|
name = 'Anthropic Claude';
|
|
31
31
|
is_real = true;
|
|
32
32
|
async fetchUsage(byok_key, opts) {
|
|
33
|
+
// group_by=model 必传 — 否则 result.model 返 null (Anthropic API doc 明确)
|
|
34
|
+
// 没 model 维度数据下游"模型细分省钱建议"无法生成
|
|
33
35
|
const params = new URLSearchParams({
|
|
34
36
|
starting_at: opts.start_date.toISOString(),
|
|
35
37
|
ending_at: opts.end_date.toISOString(),
|
|
36
38
|
bucket_width: '1d',
|
|
37
39
|
limit: String(opts.limit ?? 100),
|
|
38
40
|
});
|
|
41
|
+
params.append('group_by[]', 'model');
|
|
39
42
|
let url = `${BASE_URL}/v1/organizations/usage_report/messages?${params}`;
|
|
40
43
|
const records = [];
|
|
41
44
|
while (url) {
|