@skillfm/local 2.7.3 → 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/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/index.d.ts +6 -0
- package/dist/mcp/tools/index.d.ts.map +1 -1
- package/dist/mcp/tools/index.js +37 -0
- 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/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 @@
|
|
|
1
|
+
{"version":3,"file":"e1-router.js","sourceRoot":"","sources":["../../src/save-token/e1-router.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { LocalUsageStore } from '../usage-local/store.js';
|
|
2
|
+
import type { SaveTokenSuggestion, SaveTokenScanOptions } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* 扫描 + 返建议
|
|
5
|
+
*/
|
|
6
|
+
export declare function scanE2Cache(store: LocalUsageStore, opts: SaveTokenScanOptions): Promise<SaveTokenSuggestion[]>;
|
|
7
|
+
//# sourceMappingURL=e2-cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"e2-cache.d.ts","sourceRoot":"","sources":["../../src/save-token/e2-cache.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAI/D,OAAO,KAAK,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAO5E;;GAEG;AACH,wBAAsB,WAAW,CAC/B,KAAK,EAAE,eAAe,EACtB,IAAI,EAAE,oBAAoB,GACzB,OAAO,CAAC,mBAAmB,EAAE,CAAC,CA0FhC"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
// sdk/skillfm-local/src/save-token/e2-cache.ts
|
|
2
|
+
//
|
|
3
|
+
// E2 Prompt Caching 自动启用 (PRD §6.3) — Free 即得真省钱.
|
|
4
|
+
//
|
|
5
|
+
// Free: 扫 trajectory 找 system prompt 重复率高 / 长 prompt → surface "启 cache 估省 ¥X"
|
|
6
|
+
// 给 cache_control 代码片段让用户手动加
|
|
7
|
+
// Pro: gateway hook auto inject cache_control breakpoint (2.7.5+)
|
|
8
|
+
//
|
|
9
|
+
// 真证据 (PRD §6.3):
|
|
10
|
+
// OpenAI 50% off cached tokens (auto, 1024+ token)
|
|
11
|
+
// Anthropic 90% off cache reads ($0.30/M vs $3.00/M, 显式 ephemeral)
|
|
12
|
+
// 真案例 1 个开发者 $720 → $72/月 = 90% off
|
|
13
|
+
import { getModelPrice, USD_TO_CNY } from '../usage-local/model-pricing.js';
|
|
14
|
+
import { timeWindow } from '../usage-local/store.js';
|
|
15
|
+
/**
|
|
16
|
+
* 哪些 provider 真支持 prompt cache
|
|
17
|
+
*/
|
|
18
|
+
const CACHE_SUPPORTED_PROVIDERS = new Set(['anthropic', 'openai', 'deepseek']);
|
|
19
|
+
/**
|
|
20
|
+
* 扫描 + 返建议
|
|
21
|
+
*/
|
|
22
|
+
export async function scanE2Cache(store, opts) {
|
|
23
|
+
const window = opts.start && opts.end
|
|
24
|
+
? { start: opts.start, end: opts.end }
|
|
25
|
+
: timeWindow('week');
|
|
26
|
+
const records = store.query(window);
|
|
27
|
+
if (records.length === 0)
|
|
28
|
+
return [];
|
|
29
|
+
// 按 (provider, model) 聚合 cache 利用率
|
|
30
|
+
const byModel = new Map();
|
|
31
|
+
for (const r of records) {
|
|
32
|
+
const key = `${r.provider}/${r.model_id}`;
|
|
33
|
+
const cur = byModel.get(key) ?? {
|
|
34
|
+
count: 0, input_tokens: 0, cache_read_tokens: 0, cache_write_tokens: 0, cost_usd: 0,
|
|
35
|
+
};
|
|
36
|
+
cur.count += 1;
|
|
37
|
+
cur.input_tokens += r.input_tokens;
|
|
38
|
+
cur.cache_read_tokens += r.cache_read_tokens;
|
|
39
|
+
cur.cache_write_tokens += r.cache_write_tokens;
|
|
40
|
+
cur.cost_usd += r.estimated_cost_usd;
|
|
41
|
+
byModel.set(key, cur);
|
|
42
|
+
}
|
|
43
|
+
const suggestions = [];
|
|
44
|
+
for (const [key, agg] of byModel) {
|
|
45
|
+
const [provider] = key.split('/');
|
|
46
|
+
if (!CACHE_SUPPORTED_PROVIDERS.has(provider))
|
|
47
|
+
continue;
|
|
48
|
+
if (agg.cost_usd < 0.5)
|
|
49
|
+
continue;
|
|
50
|
+
if (agg.count < 5)
|
|
51
|
+
continue; // 5+ 次调用才有 cache 意义
|
|
52
|
+
const totalInput = agg.input_tokens + agg.cache_read_tokens;
|
|
53
|
+
if (totalInput < 5000)
|
|
54
|
+
continue; // 累计 input 太少不值得 cache
|
|
55
|
+
const cache_hit_rate = totalInput > 0 ? agg.cache_read_tokens / totalInput : 0;
|
|
56
|
+
// 如果 cache hit rate < 30% + 平均 input > 1024 tokens (cache 阈值) → 推荐启
|
|
57
|
+
const avg_input = agg.input_tokens / agg.count;
|
|
58
|
+
if (cache_hit_rate >= 0.3)
|
|
59
|
+
continue; // 已经在用 cache, skip
|
|
60
|
+
if (avg_input < 1024 && provider === 'openai')
|
|
61
|
+
continue; // OpenAI auto cache 阈值
|
|
62
|
+
if (avg_input < 200)
|
|
63
|
+
continue; // 太短不值得显式 cache
|
|
64
|
+
// 估算启 cache 后省多少
|
|
65
|
+
// 假设 cache hit rate 提到 70% (合理水平)
|
|
66
|
+
const targetCacheRate = 0.7;
|
|
67
|
+
const newCacheRead = totalInput * targetCacheRate;
|
|
68
|
+
const newRawInput = totalInput * (1 - targetCacheRate);
|
|
69
|
+
const price = getModelPrice(provider, key.split('/').slice(1).join('/'));
|
|
70
|
+
const oldCost = (agg.input_tokens / 1_000_000) * price.input_per_1m
|
|
71
|
+
+ (agg.cache_read_tokens / 1_000_000) * price.cache_read_per_1m;
|
|
72
|
+
const newCost = (newRawInput / 1_000_000) * price.input_per_1m
|
|
73
|
+
+ (newCacheRead / 1_000_000) * price.cache_read_per_1m
|
|
74
|
+
+ (totalInput * 0.1 / 1_000_000) * price.cache_write_per_1m; // 估 cache write 是 input 10%
|
|
75
|
+
const savings_usd = oldCost - newCost;
|
|
76
|
+
if (savings_usd <= 0)
|
|
77
|
+
continue;
|
|
78
|
+
const savings_pct = (savings_usd / oldCost) * 100;
|
|
79
|
+
const monthly_savings_usd = savings_usd * (30 / 7);
|
|
80
|
+
const fix_method = opts.is_pro ? 'pro_auto' : 'free_manual';
|
|
81
|
+
suggestions.push({
|
|
82
|
+
engine: 'E2_cache',
|
|
83
|
+
headline: `${key} ${agg.count} 次调用 cache 命中率 ${(cache_hit_rate * 100).toFixed(0)}% — 启 cache 可省 ${Math.round(savings_pct)}% input cost`,
|
|
84
|
+
estimated_savings_pct: Math.round(savings_pct),
|
|
85
|
+
estimated_savings_tokens: Math.round(totalInput * (30 / 7) * targetCacheRate),
|
|
86
|
+
estimated_savings_cny: Math.round(monthly_savings_usd * USD_TO_CNY * 100) / 100,
|
|
87
|
+
fix_method,
|
|
88
|
+
fix_instructions: opts.is_pro ? undefined : buildCacheInstructions(provider),
|
|
89
|
+
pro_unlock_label: opts.is_pro
|
|
90
|
+
? undefined
|
|
91
|
+
: `Pro 升级后 SkillFM gateway auto inject cache_control — 估月省 ¥${Math.round(monthly_savings_usd * USD_TO_CNY)}`,
|
|
92
|
+
details: {
|
|
93
|
+
model: key,
|
|
94
|
+
avg_input_tokens: Math.round(avg_input),
|
|
95
|
+
current_cache_hit_rate: cache_hit_rate,
|
|
96
|
+
target_cache_hit_rate: targetCacheRate,
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
return suggestions.sort((a, b) => b.estimated_savings_cny - a.estimated_savings_cny);
|
|
101
|
+
}
|
|
102
|
+
function buildCacheInstructions(provider) {
|
|
103
|
+
switch (provider) {
|
|
104
|
+
case 'anthropic':
|
|
105
|
+
return [
|
|
106
|
+
'在 system prompt 里加 cache_control breakpoint:',
|
|
107
|
+
'```',
|
|
108
|
+
'{role: "system", content: [{',
|
|
109
|
+
' type: "text",',
|
|
110
|
+
' text: "你的长 system prompt...",',
|
|
111
|
+
' cache_control: {type: "ephemeral"}', // ephemeral 5 min cache
|
|
112
|
+
'}]}',
|
|
113
|
+
'```',
|
|
114
|
+
'价: cache write +25%, cache read 90% off (vs 普通 input)',
|
|
115
|
+
].join('\n');
|
|
116
|
+
case 'openai':
|
|
117
|
+
return [
|
|
118
|
+
'OpenAI 自动 cache (1024+ token) — 无需 code 改, 但要保证 prompt 前缀稳定:',
|
|
119
|
+
'- 不要每次 inject 时间戳 / 随机 ID 在 prompt 顶',
|
|
120
|
+
'- 把 system + few-shot 例子放最前 (这样 prefix 稳定 → 自动 cache hit)',
|
|
121
|
+
].join('\n');
|
|
122
|
+
case 'deepseek':
|
|
123
|
+
return 'DeepSeek 类似 OpenAI 自动 prefix cache, 保证 prompt 前缀稳定即可';
|
|
124
|
+
default:
|
|
125
|
+
return '该 provider 暂不支持 prompt cache';
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=e2-cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"e2-cache.js","sourceRoot":"","sources":["../../src/save-token/e2-cache.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { LocalUsageStore } from '../usage-local/store.js';
|
|
2
|
+
import type { SaveTokenSuggestion, SaveTokenScanOptions } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* 检测 batch 候选: 深夜调用 (00:00-06:00) 或 短时间内 5+ 调用 (批量类)
|
|
5
|
+
*/
|
|
6
|
+
export declare function scanE3Batch(store: LocalUsageStore, opts: SaveTokenScanOptions): Promise<SaveTokenSuggestion[]>;
|
|
7
|
+
//# sourceMappingURL=e3-batch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"e3-batch.d.ts","sourceRoot":"","sources":["../../src/save-token/e3-batch.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAI/D,OAAO,KAAK,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAO5E;;GAEG;AACH,wBAAsB,WAAW,CAC/B,KAAK,EAAE,eAAe,EACtB,IAAI,EAAE,oBAAoB,GACzB,OAAO,CAAC,mBAAmB,EAAE,CAAC,CA+DhC"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// sdk/skillfm-local/src/save-token/e3-batch.ts
|
|
2
|
+
//
|
|
3
|
+
// E3 Batch API 推荐 (PRD §6.4) — 50% 即得 (异步任务).
|
|
4
|
+
//
|
|
5
|
+
// Free: 找 latency-tolerant task (深夜跑 / 批量同类 / 长完成时间) → 提示走 batch
|
|
6
|
+
// Pro: gateway 自动 dispatch batch (2.7.5+)
|
|
7
|
+
//
|
|
8
|
+
// 真证据:
|
|
9
|
+
// OpenAI Batch API 50% off all models, 24h window
|
|
10
|
+
// Anthropic Message Batches 同 50%
|
|
11
|
+
// Stack: cache + batch = 75-95% off
|
|
12
|
+
import { USD_TO_CNY } from '../usage-local/model-pricing.js';
|
|
13
|
+
import { timeWindow } from '../usage-local/store.js';
|
|
14
|
+
/**
|
|
15
|
+
* Batch API 真支持 provider
|
|
16
|
+
*/
|
|
17
|
+
const BATCH_SUPPORTED_PROVIDERS = new Set(['openai', 'anthropic']);
|
|
18
|
+
/**
|
|
19
|
+
* 检测 batch 候选: 深夜调用 (00:00-06:00) 或 短时间内 5+ 调用 (批量类)
|
|
20
|
+
*/
|
|
21
|
+
export async function scanE3Batch(store, opts) {
|
|
22
|
+
const window = opts.start && opts.end
|
|
23
|
+
? { start: opts.start, end: opts.end }
|
|
24
|
+
: timeWindow('week');
|
|
25
|
+
const records = store.query(window);
|
|
26
|
+
if (records.length === 0)
|
|
27
|
+
return [];
|
|
28
|
+
// 找深夜调用 (00:00-06:00 in Asia/Shanghai)
|
|
29
|
+
const nightRecords = records.filter((r) => {
|
|
30
|
+
if (!BATCH_SUPPORTED_PROVIDERS.has(r.provider.toLowerCase()))
|
|
31
|
+
return false;
|
|
32
|
+
const d = new Date(r.timestamp);
|
|
33
|
+
// 转 Asia/Shanghai 小时 (UTC+8)
|
|
34
|
+
const shanghaiHour = (d.getUTCHours() + 8) % 24;
|
|
35
|
+
return shanghaiHour < 6 || shanghaiHour >= 23;
|
|
36
|
+
});
|
|
37
|
+
if (nightRecords.length === 0)
|
|
38
|
+
return [];
|
|
39
|
+
// 算这些 record 总成本 + 估省 50%
|
|
40
|
+
let total_cost_usd = 0;
|
|
41
|
+
let total_tokens = 0;
|
|
42
|
+
const providerCount = new Map();
|
|
43
|
+
for (const r of nightRecords) {
|
|
44
|
+
total_cost_usd += r.estimated_cost_usd;
|
|
45
|
+
total_tokens += r.input_tokens + r.output_tokens;
|
|
46
|
+
providerCount.set(r.provider, (providerCount.get(r.provider) ?? 0) + 1);
|
|
47
|
+
}
|
|
48
|
+
if (total_cost_usd < 0.5)
|
|
49
|
+
return []; // 太少不值得
|
|
50
|
+
const savings_usd = total_cost_usd * 0.5;
|
|
51
|
+
const monthly_savings_usd = savings_usd * (30 / 7);
|
|
52
|
+
const monthly_savings_tokens = total_tokens * (30 / 7);
|
|
53
|
+
const providerList = Array.from(providerCount.entries())
|
|
54
|
+
.map(([p, c]) => `${p} ${c} 次`)
|
|
55
|
+
.join(', ');
|
|
56
|
+
const fix_method = opts.is_pro ? 'pro_auto' : 'free_manual';
|
|
57
|
+
return [{
|
|
58
|
+
engine: 'E3_batch',
|
|
59
|
+
headline: `深夜调用 ${nightRecords.length} 次 (${providerList}, ¥${(total_cost_usd * USD_TO_CNY).toFixed(2)}) — 走 batch API 50% off`,
|
|
60
|
+
estimated_savings_pct: 50,
|
|
61
|
+
estimated_savings_tokens: Math.round(monthly_savings_tokens),
|
|
62
|
+
estimated_savings_cny: Math.round(monthly_savings_usd * USD_TO_CNY * 100) / 100,
|
|
63
|
+
fix_method,
|
|
64
|
+
fix_instructions: opts.is_pro ? undefined : [
|
|
65
|
+
'深夜任务 (你不在等结果) 改走 Batch API 即 50% off:',
|
|
66
|
+
'- OpenAI: POST /v1/batches + 上传 JSONL, 24h 内返结果 (50% off)',
|
|
67
|
+
'- Anthropic: POST /v1/messages/batches 同上',
|
|
68
|
+
'在你的 agent / script 里, 把这类异步任务排队上传, 而非实时调用',
|
|
69
|
+
].join('\n'),
|
|
70
|
+
pro_unlock_label: opts.is_pro
|
|
71
|
+
? undefined
|
|
72
|
+
: `Pro 升级后 SkillFM gateway 自动 dispatch latency-tolerant task 到 Batch API — 估月省 ¥${Math.round(monthly_savings_usd * USD_TO_CNY)}`,
|
|
73
|
+
details: {
|
|
74
|
+
night_call_count: nightRecords.length,
|
|
75
|
+
provider_breakdown: Object.fromEntries(providerCount),
|
|
76
|
+
total_cost_usd_window: total_cost_usd,
|
|
77
|
+
},
|
|
78
|
+
}];
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=e3-batch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"e3-batch.js","sourceRoot":"","sources":["../../src/save-token/e3-batch.ts"],"names":[],"mappings":"AAAA,+CAA+C;AAC/C,EAAE;AACF,8CAA8C;AAC9C,EAAE;AACF,iEAAiE;AACjE,0CAA0C;AAC1C,EAAE;AACF,OAAO;AACP,oDAAoD;AACpD,oCAAoC;AACpC,sCAAsC;AAGtC,OAAO,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAIrD;;GAEG;AACH,MAAM,yBAAyB,GAAG,IAAI,GAAG,CAAC,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC;AAEnE;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,KAAsB,EACtB,IAA0B;IAE1B,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,GAAG;QACnC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE;QACtC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;IAEvB,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACpC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAEpC,uCAAuC;IACvC,MAAM,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE;QACxC,IAAI,CAAC,yBAAyB,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC;YAAE,OAAO,KAAK,CAAC;QAC3E,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QAChC,6BAA6B;QAC7B,MAAM,YAAY,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;QAChD,OAAO,YAAY,GAAG,CAAC,IAAI,YAAY,IAAI,EAAE,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAEzC,0BAA0B;IAC1B,IAAI,cAAc,GAAG,CAAC,CAAC;IACvB,IAAI,YAAY,GAAG,CAAC,CAAC;IACrB,MAAM,aAAa,GAAG,IAAI,GAAG,EAAkB,CAAC;IAChD,KAAK,MAAM,CAAC,IAAI,YAAY,EAAE,CAAC;QAC7B,cAAc,IAAI,CAAC,CAAC,kBAAkB,CAAC;QACvC,YAAY,IAAI,CAAC,CAAC,YAAY,GAAG,CAAC,CAAC,aAAa,CAAC;QACjD,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1E,CAAC;IAED,IAAI,cAAc,GAAG,GAAG;QAAE,OAAO,EAAE,CAAC,CAAC,QAAQ;IAE7C,MAAM,WAAW,GAAG,cAAc,GAAG,GAAG,CAAC;IACzC,MAAM,mBAAmB,GAAG,WAAW,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;IACnD,MAAM,sBAAsB,GAAG,YAAY,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;IAEvD,MAAM,YAAY,GAAG,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,CAAC;SACrD,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;SAC9B,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,aAAa,CAAC;IAE5D,OAAO,CAAC;YACN,MAAM,EAAE,UAAU;YAClB,QAAQ,EAAE,QAAQ,YAAY,CAAC,MAAM,OAAO,YAAY,MAAM,CAAC,cAAc,GAAG,UAAU,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,yBAAyB;YAC/H,qBAAqB,EAAE,EAAE;YACzB,wBAAwB,EAAE,IAAI,CAAC,KAAK,CAAC,sBAAsB,CAAC;YAC5D,qBAAqB,EAAE,IAAI,CAAC,KAAK,CAAC,mBAAmB,GAAG,UAAU,GAAG,GAAG,CAAC,GAAG,GAAG;YAC/E,UAAU;YACV,gBAAgB,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;gBAC1C,uCAAuC;gBACvC,2DAA2D;gBAC3D,2CAA2C;gBAC3C,2CAA2C;aAC5C,CAAC,IAAI,CAAC,IAAI,CAAC;YACZ,gBAAgB,EAAE,IAAI,CAAC,MAAM;gBAC3B,CAAC,CAAC,SAAS;gBACX,CAAC,CAAC,gFAAgF,IAAI,CAAC,KAAK,CAAC,mBAAmB,GAAG,UAAU,CAAC,EAAE;YAClI,OAAO,EAAE;gBACP,gBAAgB,EAAE,YAAY,CAAC,MAAM;gBACrC,kBAAkB,EAAE,MAAM,CAAC,WAAW,CAAC,aAAa,CAAC;gBACrD,qBAAqB,EAAE,cAAc;aACtC;SACF,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { GatewayDetection } from './types.js';
|
|
2
|
+
export declare const SKILLFM_GATEWAY_BASE_URL: string;
|
|
3
|
+
/**
|
|
4
|
+
* 检测各 IDE 的配置 + 当前 BASE_URL
|
|
5
|
+
*/
|
|
6
|
+
export declare function detectIDEs(): Promise<GatewayDetection[]>;
|
|
7
|
+
/**
|
|
8
|
+
* 配置一个 IDE 的 gateway BASE_URL (写 config + 提供 revert 命令)
|
|
9
|
+
*
|
|
10
|
+
* 真改: 在每个 config 加 ANTHROPIC_BASE_URL / OPENAI_API_BASE 指向 SkillFM gateway
|
|
11
|
+
* 透明: 改之前 backup 原 config 到 ~/.skillfm/gateway-backup/<ts>/
|
|
12
|
+
*/
|
|
13
|
+
export interface SetupResult {
|
|
14
|
+
ide: string;
|
|
15
|
+
applied: boolean;
|
|
16
|
+
config_path?: string;
|
|
17
|
+
backup_path?: string;
|
|
18
|
+
revert_command?: string;
|
|
19
|
+
error?: string;
|
|
20
|
+
}
|
|
21
|
+
export declare function setupClaudeCodeGateway(): Promise<SetupResult>;
|
|
22
|
+
export declare function setupShellEnvGateway(): Promise<SetupResult>;
|
|
23
|
+
/**
|
|
24
|
+
* 一键配 — 所有检测到的 IDE
|
|
25
|
+
*/
|
|
26
|
+
export declare function setupAllDetectedGateways(): Promise<SetupResult[]>;
|
|
27
|
+
//# sourceMappingURL=gateway-setup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gateway-setup.d.ts","sourceRoot":"","sources":["../../src/save-token/gateway-setup.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,gBAAgB,EAAsB,MAAM,YAAY,CAAC;AAEvE,eAAO,MAAM,wBAAwB,QAAuE,CAAC;AAE7G;;GAEG;AACH,wBAAsB,UAAU,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAsB9D;AAyFD;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,WAAW,CAAC,CAiCnE;AAED,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,WAAW,CAAC,CAoCjE;AAED;;GAEG;AACH,wBAAsB,wBAAwB,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC,CAcvE"}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
// sdk/skillfm-local/src/save-token/gateway-setup.ts
|
|
2
|
+
//
|
|
3
|
+
// LLM Gateway Onboarding 一键配置 (PRD V1.3 §3.4 + 决策 #8).
|
|
4
|
+
// Eric 拍板: Day 0 一次问授权, Pro 升级 0 摩擦.
|
|
5
|
+
//
|
|
6
|
+
// 真核心:
|
|
7
|
+
// 1. detectIDEs() — 看 PATH / 已知配置目录, 检测用户用啥 IDE
|
|
8
|
+
// 2. setupGateway() — 改 IDE config 把 ANTHROPIC_BASE_URL / OPENAI_API_BASE 指向 SkillFM gateway
|
|
9
|
+
// 3. revertGateway() — 1 行 unset 命令让用户随时回滚
|
|
10
|
+
//
|
|
11
|
+
// 透明性: 改任何文件前 surface 给用户 + 提供 revert 命令.
|
|
12
|
+
// MVP: gateway 端 URL 用 placeholder (https://gateway.skillfm.ai), 真 gateway 服务 2.7.5 上线.
|
|
13
|
+
import * as fs from 'node:fs';
|
|
14
|
+
import * as path from 'node:path';
|
|
15
|
+
import { homedir } from 'node:os';
|
|
16
|
+
export const SKILLFM_GATEWAY_BASE_URL = process.env.SKILLFM_GATEWAY_BASE_URL ?? 'https://gateway.skillfm.ai';
|
|
17
|
+
/**
|
|
18
|
+
* 检测各 IDE 的配置 + 当前 BASE_URL
|
|
19
|
+
*/
|
|
20
|
+
export async function detectIDEs() {
|
|
21
|
+
const out = [];
|
|
22
|
+
// Claude Code: ~/.claude/settings.json
|
|
23
|
+
out.push(await detectClaudeCode());
|
|
24
|
+
// Cursor: ~/Library/Application Support/Cursor/User/settings.json (Mac)
|
|
25
|
+
out.push(await detectCursor());
|
|
26
|
+
// Codex: ~/.codex/config.json
|
|
27
|
+
out.push(await detectCodex());
|
|
28
|
+
// Aider: env CHECK
|
|
29
|
+
out.push(await detectAider());
|
|
30
|
+
// Continue: ~/.continue/config.json
|
|
31
|
+
out.push(await detectContinue());
|
|
32
|
+
// Shell env (zsh / bash)
|
|
33
|
+
out.push(await detectShellEnv());
|
|
34
|
+
return out;
|
|
35
|
+
}
|
|
36
|
+
async function detectClaudeCode() {
|
|
37
|
+
const settingsPath = path.join(homedir(), '.claude', 'settings.json');
|
|
38
|
+
const exists = fs.existsSync(settingsPath);
|
|
39
|
+
let current_base_url;
|
|
40
|
+
let setup_status = 'not_configured';
|
|
41
|
+
if (exists) {
|
|
42
|
+
try {
|
|
43
|
+
const content = await fs.promises.readFile(settingsPath, 'utf-8');
|
|
44
|
+
const settings = JSON.parse(content);
|
|
45
|
+
current_base_url = settings.env?.ANTHROPIC_BASE_URL;
|
|
46
|
+
setup_status = current_base_url?.includes('skillfm') ? 'configured' : 'not_configured';
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
setup_status = 'unknown';
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
ide: 'claude-code',
|
|
54
|
+
detected: exists,
|
|
55
|
+
config_path: exists ? settingsPath : undefined,
|
|
56
|
+
current_base_url,
|
|
57
|
+
setup_status,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
async function detectCursor() {
|
|
61
|
+
const cursorDir = path.join(homedir(), 'Library', 'Application Support', 'Cursor');
|
|
62
|
+
const detected = fs.existsSync(cursorDir);
|
|
63
|
+
return {
|
|
64
|
+
ide: 'cursor',
|
|
65
|
+
detected,
|
|
66
|
+
config_path: detected ? path.join(cursorDir, 'User', 'settings.json') : undefined,
|
|
67
|
+
setup_status: detected ? 'not_configured' : 'unknown',
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
async function detectCodex() {
|
|
71
|
+
const cfgPath = path.join(homedir(), '.codex', 'config.json');
|
|
72
|
+
const exists = fs.existsSync(cfgPath);
|
|
73
|
+
return {
|
|
74
|
+
ide: 'codex',
|
|
75
|
+
detected: exists,
|
|
76
|
+
config_path: exists ? cfgPath : undefined,
|
|
77
|
+
setup_status: exists ? 'not_configured' : 'unknown',
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
async function detectAider() {
|
|
81
|
+
// Aider 用 env 配, 没固定 config 文件
|
|
82
|
+
return {
|
|
83
|
+
ide: 'aider',
|
|
84
|
+
detected: false, // 简化: MVP 不主动检测 aider, 用户手动配
|
|
85
|
+
setup_status: 'unknown',
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
async function detectContinue() {
|
|
89
|
+
const cfgPath = path.join(homedir(), '.continue', 'config.json');
|
|
90
|
+
const exists = fs.existsSync(cfgPath);
|
|
91
|
+
return {
|
|
92
|
+
ide: 'continue',
|
|
93
|
+
detected: exists,
|
|
94
|
+
config_path: exists ? cfgPath : undefined,
|
|
95
|
+
setup_status: exists ? 'not_configured' : 'unknown',
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
async function detectShellEnv() {
|
|
99
|
+
const current_anthropic = process.env.ANTHROPIC_BASE_URL;
|
|
100
|
+
const current_openai = process.env.OPENAI_API_BASE;
|
|
101
|
+
const isConfigured = !!(current_anthropic?.includes('skillfm') || current_openai?.includes('skillfm'));
|
|
102
|
+
// 检测 shell rc
|
|
103
|
+
const zshrc = path.join(homedir(), '.zshrc');
|
|
104
|
+
const bashrc = path.join(homedir(), '.bashrc');
|
|
105
|
+
const cfgPath = fs.existsSync(zshrc) ? zshrc : fs.existsSync(bashrc) ? bashrc : undefined;
|
|
106
|
+
return {
|
|
107
|
+
ide: 'shell-env',
|
|
108
|
+
detected: !!cfgPath,
|
|
109
|
+
config_path: cfgPath,
|
|
110
|
+
current_base_url: current_anthropic ?? current_openai,
|
|
111
|
+
setup_status: isConfigured ? 'configured' : 'not_configured',
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
export async function setupClaudeCodeGateway() {
|
|
115
|
+
const settingsPath = path.join(homedir(), '.claude', 'settings.json');
|
|
116
|
+
const ide = 'claude-code';
|
|
117
|
+
if (!fs.existsSync(settingsPath)) {
|
|
118
|
+
// Claude Code 不存在 → skip
|
|
119
|
+
return { ide, applied: false, error: 'Claude Code not detected' };
|
|
120
|
+
}
|
|
121
|
+
// backup
|
|
122
|
+
const backupDir = path.join(homedir(), '.skillfm', 'gateway-backup', new Date().toISOString().replace(/[:.]/g, '-'));
|
|
123
|
+
await fs.promises.mkdir(backupDir, { recursive: true, mode: 0o700 });
|
|
124
|
+
const backupPath = path.join(backupDir, 'claude-settings.json');
|
|
125
|
+
await fs.promises.copyFile(settingsPath, backupPath);
|
|
126
|
+
// 改 config
|
|
127
|
+
try {
|
|
128
|
+
const content = await fs.promises.readFile(settingsPath, 'utf-8');
|
|
129
|
+
const settings = JSON.parse(content);
|
|
130
|
+
settings.env = settings.env ?? {};
|
|
131
|
+
settings.env.ANTHROPIC_BASE_URL = SKILLFM_GATEWAY_BASE_URL;
|
|
132
|
+
await fs.promises.writeFile(settingsPath, JSON.stringify(settings, null, 2), 'utf-8');
|
|
133
|
+
return {
|
|
134
|
+
ide,
|
|
135
|
+
applied: true,
|
|
136
|
+
config_path: settingsPath,
|
|
137
|
+
backup_path: backupPath,
|
|
138
|
+
revert_command: `cp "${backupPath}" "${settingsPath}"`,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
catch (e) {
|
|
142
|
+
return { ide, applied: false, error: e.message };
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
export async function setupShellEnvGateway() {
|
|
146
|
+
const ide = 'shell-env';
|
|
147
|
+
const zshrc = path.join(homedir(), '.zshrc');
|
|
148
|
+
const bashrc = path.join(homedir(), '.bashrc');
|
|
149
|
+
const rcPath = fs.existsSync(zshrc) ? zshrc : fs.existsSync(bashrc) ? bashrc : null;
|
|
150
|
+
if (!rcPath) {
|
|
151
|
+
return { ide, applied: false, error: 'No shell rc found' };
|
|
152
|
+
}
|
|
153
|
+
const backupDir = path.join(homedir(), '.skillfm', 'gateway-backup', new Date().toISOString().replace(/[:.]/g, '-'));
|
|
154
|
+
await fs.promises.mkdir(backupDir, { recursive: true, mode: 0o700 });
|
|
155
|
+
const backupPath = path.join(backupDir, path.basename(rcPath));
|
|
156
|
+
await fs.promises.copyFile(rcPath, backupPath);
|
|
157
|
+
const block = [
|
|
158
|
+
'',
|
|
159
|
+
'# === SkillFM Gateway (added by skillfm_setup_gateway) ===',
|
|
160
|
+
`export ANTHROPIC_BASE_URL="${SKILLFM_GATEWAY_BASE_URL}/anthropic"`,
|
|
161
|
+
`export OPENAI_API_BASE="${SKILLFM_GATEWAY_BASE_URL}/openai"`,
|
|
162
|
+
'# === SkillFM Gateway end ===',
|
|
163
|
+
'',
|
|
164
|
+
].join('\n');
|
|
165
|
+
try {
|
|
166
|
+
await fs.promises.appendFile(rcPath, block, 'utf-8');
|
|
167
|
+
return {
|
|
168
|
+
ide,
|
|
169
|
+
applied: true,
|
|
170
|
+
config_path: rcPath,
|
|
171
|
+
backup_path: backupPath,
|
|
172
|
+
revert_command: `cp "${backupPath}" "${rcPath}" && source "${rcPath}"`,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
catch (e) {
|
|
176
|
+
return { ide, applied: false, error: e.message };
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* 一键配 — 所有检测到的 IDE
|
|
181
|
+
*/
|
|
182
|
+
export async function setupAllDetectedGateways() {
|
|
183
|
+
const detections = await detectIDEs();
|
|
184
|
+
const results = [];
|
|
185
|
+
for (const d of detections) {
|
|
186
|
+
if (!d.detected)
|
|
187
|
+
continue;
|
|
188
|
+
if (d.setup_status === 'configured') {
|
|
189
|
+
results.push({ ide: d.ide, applied: false, error: 'already configured' });
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
if (d.ide === 'claude-code')
|
|
193
|
+
results.push(await setupClaudeCodeGateway());
|
|
194
|
+
else if (d.ide === 'shell-env')
|
|
195
|
+
results.push(await setupShellEnvGateway());
|
|
196
|
+
// Cursor / Codex / Aider / Continue: MVP 仅 surface 提示用户手动配 (UI 复杂)
|
|
197
|
+
}
|
|
198
|
+
return results;
|
|
199
|
+
}
|
|
200
|
+
//# sourceMappingURL=gateway-setup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gateway-setup.js","sourceRoot":"","sources":["../../src/save-token/gateway-setup.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type { EngineId, FixMethod, SaveTokenSuggestion, SaveTokenScanOptions, GatewaySetupStatus, GatewayDetection, } from './types.js';
|
|
2
|
+
export { scanE1Router } from './e1-router.js';
|
|
3
|
+
export { scanE2Cache } from './e2-cache.js';
|
|
4
|
+
export { scanE3Batch } from './e3-batch.js';
|
|
5
|
+
export { detectIDEs, setupClaudeCodeGateway, setupShellEnvGateway, setupAllDetectedGateways, SKILLFM_GATEWAY_BASE_URL, } from './gateway-setup.js';
|
|
6
|
+
export type { SetupResult } from './gateway-setup.js';
|
|
7
|
+
import type { LocalUsageStore } from '../usage-local/store.js';
|
|
8
|
+
import type { SaveTokenSuggestion, SaveTokenScanOptions } from './types.js';
|
|
9
|
+
/**
|
|
10
|
+
* 跑全 engine 扫描 (E1+E2+E3 并行) — 主入口用
|
|
11
|
+
*/
|
|
12
|
+
export declare function scanAllEngines(store: LocalUsageStore, opts: SaveTokenScanOptions): Promise<SaveTokenSuggestion[]>;
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/save-token/index.ts"],"names":[],"mappings":"AAKA,YAAY,EACV,QAAQ,EACR,SAAS,EACT,mBAAmB,EACnB,oBAAoB,EACpB,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EACL,UAAU,EACV,sBAAsB,EACtB,oBAAoB,EACpB,wBAAwB,EACxB,wBAAwB,GACzB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,KAAK,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAK5E;;GAEG;AACH,wBAAsB,cAAc,CAClC,KAAK,EAAE,eAAe,EACtB,IAAI,EAAE,oBAAoB,GACzB,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAOhC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// sdk/skillfm-local/src/save-token/index.ts
|
|
2
|
+
//
|
|
3
|
+
// Save Token Engine — public API.
|
|
4
|
+
// 真"省 token" 5 大引擎 (PRD V1.3 §6).
|
|
5
|
+
export { scanE1Router } from './e1-router.js';
|
|
6
|
+
export { scanE2Cache } from './e2-cache.js';
|
|
7
|
+
export { scanE3Batch } from './e3-batch.js';
|
|
8
|
+
export { detectIDEs, setupClaudeCodeGateway, setupShellEnvGateway, setupAllDetectedGateways, SKILLFM_GATEWAY_BASE_URL, } from './gateway-setup.js';
|
|
9
|
+
import { scanE1Router } from './e1-router.js';
|
|
10
|
+
import { scanE2Cache } from './e2-cache.js';
|
|
11
|
+
import { scanE3Batch } from './e3-batch.js';
|
|
12
|
+
/**
|
|
13
|
+
* 跑全 engine 扫描 (E1+E2+E3 并行) — 主入口用
|
|
14
|
+
*/
|
|
15
|
+
export async function scanAllEngines(store, opts) {
|
|
16
|
+
const [e1, e2, e3] = await Promise.all([
|
|
17
|
+
scanE1Router(store, opts),
|
|
18
|
+
scanE2Cache(store, opts),
|
|
19
|
+
scanE3Batch(store, opts),
|
|
20
|
+
]);
|
|
21
|
+
return [...e1, ...e2, ...e3].sort((a, b) => b.estimated_savings_cny - a.estimated_savings_cny);
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/save-token/index.ts"],"names":[],"mappings":"AAAA,4CAA4C;AAC5C,EAAE;AACF,kCAAkC;AAClC,kCAAkC;AAUlC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EACL,UAAU,EACV,sBAAsB,EACtB,oBAAoB,EACpB,wBAAwB,EACxB,wBAAwB,GACzB,MAAM,oBAAoB,CAAC;AAK5B,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,KAAsB,EACtB,IAA0B;IAE1B,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QACrC,YAAY,CAAC,KAAK,EAAE,IAAI,CAAC;QACzB,WAAW,CAAC,KAAK,EAAE,IAAI,CAAC;QACxB,WAAW,CAAC,KAAK,EAAE,IAAI,CAAC;KACzB,CAAC,CAAC;IACH,OAAO,CAAC,GAAG,EAAE,EAAE,GAAG,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,qBAAqB,GAAG,CAAC,CAAC,qBAAqB,CAAC,CAAC;AACjG,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export type EngineId = 'E1_router' | 'E2_cache' | 'E3_batch' | 'E4_compress' | 'E5_rotate';
|
|
2
|
+
export type FixMethod = 'free_manual' | 'pro_auto' | 'pro_locked';
|
|
3
|
+
/**
|
|
4
|
+
* 一条省 token 建议 (来自任一 engine 的扫描)
|
|
5
|
+
*/
|
|
6
|
+
export interface SaveTokenSuggestion {
|
|
7
|
+
engine: EngineId;
|
|
8
|
+
/** 短文案 — surface 给 agent / 用户 (e.g. "5 次 Sonnet 可切 Haiku") */
|
|
9
|
+
headline: string;
|
|
10
|
+
/** 估算省 token 百分比 (0-100) */
|
|
11
|
+
estimated_savings_pct: number;
|
|
12
|
+
/** 估算月省 token (基于过去 7 天日均) */
|
|
13
|
+
estimated_savings_tokens: number;
|
|
14
|
+
/** 估算月省 CNY (基于价目表) */
|
|
15
|
+
estimated_savings_cny: number;
|
|
16
|
+
/** 修法 */
|
|
17
|
+
fix_method: FixMethod;
|
|
18
|
+
/** Free 用户手动操作步骤 */
|
|
19
|
+
fix_instructions?: string;
|
|
20
|
+
/** Pro 升级文案 */
|
|
21
|
+
pro_unlock_label?: string;
|
|
22
|
+
/** Engine 详情 — 比如哪个 model / 哪个 prompt 触发了建议 */
|
|
23
|
+
details?: Record<string, unknown>;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Save Token Engine 扫描请求
|
|
27
|
+
*/
|
|
28
|
+
export interface SaveTokenScanOptions {
|
|
29
|
+
/** 是否 Pro 用户 */
|
|
30
|
+
is_pro: boolean;
|
|
31
|
+
/** 时间窗口 (默认近 7 天) */
|
|
32
|
+
start?: string;
|
|
33
|
+
end?: string;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Gateway setup 状态 (per IDE)
|
|
37
|
+
*/
|
|
38
|
+
export type GatewaySetupStatus = 'not_configured' | 'configured' | 'partial' | 'unknown';
|
|
39
|
+
export interface GatewayDetection {
|
|
40
|
+
ide: 'claude-code' | 'cursor' | 'codex' | 'aider' | 'continue' | 'shell-env';
|
|
41
|
+
detected: boolean;
|
|
42
|
+
config_path?: string;
|
|
43
|
+
current_base_url?: string;
|
|
44
|
+
setup_status: GatewaySetupStatus;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/save-token/types.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,QAAQ,GAChB,WAAW,GACX,UAAU,GACV,UAAU,GACV,aAAa,GACb,WAAW,CAAC;AAEhB,MAAM,MAAM,SAAS,GAAG,aAAa,GAAG,UAAU,GAAG,YAAY,CAAC;AAElE;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,QAAQ,CAAC;IACjB,8DAA8D;IAC9D,QAAQ,EAAE,MAAM,CAAC;IACjB,4BAA4B;IAC5B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,8BAA8B;IAC9B,wBAAwB,EAAE,MAAM,CAAC;IACjC,uBAAuB;IACvB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,SAAS;IACT,UAAU,EAAE,SAAS,CAAC;IACtB,oBAAoB;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,eAAe;IACf,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,+CAA+C;IAC/C,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,gBAAgB;IAChB,MAAM,EAAE,OAAO,CAAC;IAChB,qBAAqB;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAC1B,gBAAgB,GAChB,YAAY,GACZ,SAAS,GACT,SAAS,CAAC;AAEd,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,aAAa,GAAG,QAAQ,GAAG,OAAO,GAAG,OAAO,GAAG,UAAU,GAAG,WAAW,CAAC;IAC7E,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,kBAAkB,CAAC;CAClC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/save-token/types.ts"],"names":[],"mappings":"AAAA,4CAA4C;AAC5C,EAAE;AACF,+CAA+C"}
|