sandoichi 0.4.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # sandoichi
2
2
 
3
- `sandoichi` is Sando's optional JavaScript library. The full Sando plugin is the main product. Install it through the Claude Code or Codex marketplace.
3
+ `sandoichi` is Sando's optional JavaScript library. The marketplace plugin is the main product. Install the plugin through the Claude Code or Codex marketplace.
4
4
 
5
5
  ```bash
6
6
  npm install sandoichi
@@ -24,12 +24,12 @@ Project-specific detectors can be declared in `.sando/redaction.json`:
24
24
 
25
25
  Built-ins stay enabled. Profiles are declarative and local to the current project; invalid profiles fail visibly.
26
26
 
27
- The library requires Node.js `>=22.22.0 <23` and has no runtime dependencies. Installing it does not install or enable the plugin. The plugin is the supported host surface; this package exports the context/history runtime, provider usage report, paired accounting, and explicit proxy API only.
27
+ The library requires Node.js `>=22.22.0 <23` and has no runtime dependencies. Installing it does not install or enable the plugin. The plugin remains the supported host surface; this package exports the context/history runtime, provider usage report, paired accounting, and explicit proxy API only.
28
28
 
29
- `computeWeightedUsage` and `summarizePairedSessions` keep mechanical reduction, weighted estimates, provider-reported cost, and paired-session evidence distinct. The benchmark report adds explicit replay counterfactuals. The library does not install hooks, register MCP servers, or make routing/backoff decisions for a host.
29
+ `computeWeightedUsage` and `summarizePairedSessions` keep mechanical reduction, weighted estimates, provider-reported cost, and paired-session evidence separate. The benchmark report adds explicit replay counterfactuals. The library does not install hooks, register MCP servers, or make routing/backoff decisions for a host.
30
30
 
31
31
  For plugin installation, see the [main project README](https://github.com/yuzushi-dev/Sando#readme).
32
32
 
33
33
  Telemetry is off by default. An interactive npm install asks once for consent; see the [full disclosure](https://github.com/yuzushi-dev/Sando/blob/main/TELEMETRY.md).
34
34
 
35
- MIT.
35
+ License: MIT.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sandoichi",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "Bound repeated tool-output context in Claude Code and Codex with deterministic local routing and provider accounting.",
5
5
  "license": "MIT",
6
6
  "author": "yuzushi",
@@ -38,10 +38,12 @@ function readMetricsSnapshot(metricsPath, { host, sessionId, model } = {}) {
38
38
  const providerSavings = report.cumulative.providerReportedSavingsTokens;
39
39
  const source = hasProvider && !hasEstimate && providerSavings !== null
40
40
  ? 'provider-reported' : 'estimate';
41
+ const estimatedInputTokens = records.reduce((total, item) => total + item.estimatedInputTokens, 0);
41
42
  const latest = [...records].sort((left, right) => left.at.localeCompare(right.at)).at(-1);
42
43
  return {
43
44
  updatedAt: latestAt(records), source,
44
45
  model: model ?? latest?.model,
46
+ estimatedInputTokens,
45
47
  savedTokens: source === 'provider-reported'
46
48
  ? providerSavings : report.cumulative.estimatedTransformSavingsTokens,
47
49
  };
@@ -80,23 +82,10 @@ function compactTokens(value) {
80
82
  return `${Number((value / 1_000_000).toFixed(2))}M`;
81
83
  }
82
84
 
83
- function compactTurns(value) {
84
- return `${value} ${value === 1 ? 'turn' : 'turns'}`;
85
- }
86
-
87
- export function renderStatusLine({ metrics, providerUsage, totalCostUsd } = {}, _now = Date.now()) {
88
- if (!Number.isSafeInteger(providerUsage?.totalTokens) || providerUsage.totalTokens <= 0
89
- || !Number.isSafeInteger(providerUsage?.turnCount) || providerUsage.turnCount <= 0) return '🥪 —';
90
- const parts = [
91
- `${compactTokens(providerUsage.totalTokens)} provider tokens`,
92
- compactTurns(providerUsage.turnCount),
93
- ];
94
- if (Number.isFinite(providerUsage.weightedCostUnits) && providerUsage.weightedCostUnits >= 0) {
95
- parts.push(`${compactTokens(Math.round(providerUsage.weightedCostUnits))} cost units`);
96
- }
97
- if (Number.isFinite(totalCostUsd) && totalCostUsd >= 0) {
98
- const effectiveRate = totalCostUsd / providerUsage.totalTokens;
99
- parts.push(`$${totalCostUsd.toFixed(2)}`, `$${(effectiveRate * 1_000_000).toFixed(2)}/M`);
100
- }
101
- return `🥪 ${parts.join(' · ')}`;
85
+ export function renderStatusLine({ metrics } = {}) {
86
+ if (!Number.isSafeInteger(metrics?.savedTokens) || metrics.savedTokens < 0
87
+ || !Number.isSafeInteger(metrics?.estimatedInputTokens) || metrics.estimatedInputTokens <= 0) return '🥪 —';
88
+ const percentage = Math.round(metrics.savedTokens / metrics.estimatedInputTokens * 100);
89
+ const estimate = metrics.source === 'estimate' ? '~' : '';
90
+ return `🥪 saved ${estimate}${compactTokens(metrics.savedTokens)} ctx tok (${percentage}%)`;
102
91
  }