pi-smart-compact 7.12.5 → 7.13.0
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/CHANGELOG.md +15 -0
- package/README.md +1 -1
- package/dist/constants.d.ts +1 -1
- package/dist/core.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +314 -49
- package/dist/phases/verify.d.ts.map +1 -1
- package/dist/ui/dashboard-format.d.ts +14 -0
- package/dist/ui/dashboard-format.d.ts.map +1 -0
- package/dist/ui/overlays.d.ts +8 -1
- package/dist/ui/overlays.d.ts.map +1 -1
- package/dist/utils/cache.d.ts +1 -0
- package/dist/utils/cache.d.ts.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [7.13.0] - 2026-05-25
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- **Interactive metrics dashboard TUI** — `/smart-compact dashboard` now opens an in-terminal dashboard with overview, latest-run details, current-session runs, recent runs, and an explicit HTML export action.
|
|
7
|
+
- **Dashboard run detail formatting** — Added tested formatter helpers for legacy metrics, empty states, phase timings, compact run descriptions, and bounded percentage display.
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
- **Provider cache percentage accounting** — Provider prompt-cache hit rates now use an effective prompt-token denominator and are capped at 100%, preventing impossible values such as `572610%` when providers report cached tokens separately from new input tokens.
|
|
11
|
+
- **Verification repair for malformed summaries** — Missing canonical sections are now reported as verification gaps and deterministic repair can create sections such as `## Goal`, `## Progress`, `## Critical Context`, and `## Files Modified` before injecting required facts.
|
|
12
|
+
- **Dashboard comparison noise** — Legacy metrics entries without profile/provider metadata are omitted from profile/provider comparison groups instead of appearing as misleading `unknown` rows.
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
- **Metrics readability** — Result overlays and notifications distinguish prompt, new, and cached input tokens when provider cache reads are present.
|
|
16
|
+
- **Dashboard navigation** — The TUI supports keybinding-aware navigation plus page-up/page-down and home/end scrolling.
|
|
17
|
+
|
|
3
18
|
## [7.12.5] - 2026-05-23
|
|
4
19
|
|
|
5
20
|
### Fixed
|
package/README.md
CHANGED
|
@@ -186,7 +186,7 @@ The tool prepares a pending smart summary and lets Pi consume it on the next nat
|
|
|
186
186
|
- pending summaries are kept in memory for **5 minutes**
|
|
187
187
|
- exploration is adaptive and may be skipped for simple sessions
|
|
188
188
|
- use `/smart-compact metrics` for profile/provider comparisons
|
|
189
|
-
- use `/smart-compact dashboard` to
|
|
189
|
+
- use `/smart-compact dashboard` to open the interactive TUI dashboard (overview, latest run, current session, recent runs, or write HTML)
|
|
190
190
|
|
|
191
191
|
This keeps the extension helpful without forcing extra work when it is not needed.
|
|
192
192
|
|
package/dist/constants.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Constants, prompts, and profile defaults.
|
|
3
3
|
*/
|
|
4
4
|
import type { CompressionProfile, ProfileConfig } from "./types.ts";
|
|
5
|
-
export declare const VERSION = "7.
|
|
5
|
+
export declare const VERSION = "7.13.0";
|
|
6
6
|
export declare const CHARS_PER_TOKEN = 3.8;
|
|
7
7
|
export declare const COMPACT_SYSTEM_PREFIX: string;
|
|
8
8
|
export declare const PROFILES: Record<CompressionProfile, ProfileConfig>;
|
package/dist/core.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAE/E,OAAO,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,KAAK,EACV,kBAAkB,EAAE,iBAAiB,EAEtC,MAAM,YAAY,CAAC;AAwBpB,yEAAyE;AACzE,MAAM,WAAW,mBAAmB;IAClC,GAAG,EAAE,uBAAuB,CAAC;IAC7B,YAAY,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IACzB,QAAQ,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IACrB,OAAO,EAAE,kBAAkB,CAAC;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE;QAAE,KAAK,EAAE,iBAAiB,GAAG,IAAI,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IACnE,SAAS,EAAE;QAAE,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC;IAC9B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,4EAA4E;IAC5E,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,sGAAsG;IACtG,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAsB,eAAe,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAE/E,OAAO,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,KAAK,EACV,kBAAkB,EAAE,iBAAiB,EAEtC,MAAM,YAAY,CAAC;AAwBpB,yEAAyE;AACzE,MAAM,WAAW,mBAAmB;IAClC,GAAG,EAAE,uBAAuB,CAAC;IAC7B,YAAY,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IACzB,QAAQ,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IACrB,OAAO,EAAE,kBAAkB,CAAC;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE;QAAE,KAAK,EAAE,iBAAiB,GAAG,IAAI,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IACnE,SAAS,EAAE;QAAE,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC;IAC9B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,4EAA4E;IAC5E,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,sGAAsG;IACtG,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAsB,eAAe,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAqiB9E"}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,YAAY,EAA2B,MAAM,iCAAiC,CAAC;AA0C7F,MAAM,CAAC,OAAO,UAAU,qBAAqB,CAAC,EAAE,EAAE,YAAY,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,YAAY,EAA2B,MAAM,iCAAiC,CAAC;AA0C7F,MAAM,CAAC,OAAO,UAAU,qBAAqB,CAAC,EAAE,EAAE,YAAY,QAwM7D"}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
// src/constants.ts
|
|
3
|
-
var VERSION = "7.
|
|
3
|
+
var VERSION = "7.13.0";
|
|
4
4
|
var CHARS_PER_TOKEN = 3.8;
|
|
5
5
|
var COMPACT_SYSTEM_PREFIX = "You are an expert conversation summarizer for a coding agent. " + "Produce structured markdown summaries. " + "Follow output format exactly. " + "Use EXACT names \u2014 never paraphrase code identifiers. " + "Trust deterministic extraction data over intuition.";
|
|
6
6
|
var PROFILES = {
|
|
@@ -854,6 +854,11 @@ function recordMetric(m) {
|
|
|
854
854
|
if (_metrics.length > 200)
|
|
855
855
|
_metrics.splice(0, _metrics.length - 100);
|
|
856
856
|
}
|
|
857
|
+
function effectivePromptInputTokens(inputTokens, cacheHitTokens) {
|
|
858
|
+
if (cacheHitTokens <= 0)
|
|
859
|
+
return Math.max(0, inputTokens);
|
|
860
|
+
return cacheHitTokens > inputTokens ? inputTokens + cacheHitTokens : inputTokens;
|
|
861
|
+
}
|
|
857
862
|
function getMetricsSummary() {
|
|
858
863
|
const n = _metrics.length;
|
|
859
864
|
if (!n)
|
|
@@ -862,13 +867,14 @@ function getMetricsSummary() {
|
|
|
862
867
|
const totalOutput = _metrics.reduce((s, m) => s + m.outputTokens, 0);
|
|
863
868
|
const totalCacheHit = _metrics.reduce((s, m) => s + m.cacheHitTokens, 0);
|
|
864
869
|
const avgLatency = _metrics.reduce((s, m) => s + m.latencyMs, 0) / n;
|
|
870
|
+
const cacheDenominator = effectivePromptInputTokens(totalInput, totalCacheHit);
|
|
865
871
|
return {
|
|
866
872
|
totalCalls: n,
|
|
867
873
|
totalInput,
|
|
868
874
|
totalOutput,
|
|
869
875
|
totalCacheHit,
|
|
870
876
|
avgLatency: Math.round(avgLatency),
|
|
871
|
-
cacheHitRate:
|
|
877
|
+
cacheHitRate: cacheDenominator > 0 ? Math.min(1, totalCacheHit / cacheDenominator) : 0
|
|
872
878
|
};
|
|
873
879
|
}
|
|
874
880
|
async function trackedComplete(phase, model, reqBody, opts) {
|
|
@@ -1104,9 +1110,9 @@ function summarizeDashboard(entries) {
|
|
|
1104
1110
|
successRate: entries.length ? success / entries.length : 0,
|
|
1105
1111
|
avgDuration: Math.round(average(durations)),
|
|
1106
1112
|
p95Duration: percentile(durations, 95),
|
|
1107
|
-
totalCalls: entries.reduce((sum, e) => sum + e.totalCalls, 0),
|
|
1108
|
-
totalInput: entries.reduce((sum, e) => sum + e.totalInput, 0),
|
|
1109
|
-
totalOutput: entries.reduce((sum, e) => sum + e.totalOutput, 0),
|
|
1113
|
+
totalCalls: entries.reduce((sum, e) => sum + (e.totalCalls ?? 0), 0),
|
|
1114
|
+
totalInput: entries.reduce((sum, e) => sum + (e.totalInput ?? 0), 0),
|
|
1115
|
+
totalOutput: entries.reduce((sum, e) => sum + (e.totalOutput ?? 0), 0),
|
|
1110
1116
|
totalSaved: entries.reduce((sum, e) => sum + (e.tokensSaved ?? 0), 0),
|
|
1111
1117
|
avgScore: Math.round(average(scored))
|
|
1112
1118
|
};
|
|
@@ -1114,7 +1120,9 @@ function summarizeDashboard(entries) {
|
|
|
1114
1120
|
function groupMetrics(entries, keyFn) {
|
|
1115
1121
|
const groups = new Map;
|
|
1116
1122
|
for (const entry of entries) {
|
|
1117
|
-
const key = keyFn(entry)
|
|
1123
|
+
const key = keyFn(entry);
|
|
1124
|
+
if (!key)
|
|
1125
|
+
continue;
|
|
1118
1126
|
groups.set(key, [...groups.get(key) ?? [], entry]);
|
|
1119
1127
|
}
|
|
1120
1128
|
return [...groups.entries()].map(([name, group]) => {
|
|
@@ -1128,7 +1136,7 @@ function groupMetrics(entries, keyFn) {
|
|
|
1128
1136
|
p95Duration: percentile(durations, 95),
|
|
1129
1137
|
avgScore: Math.round(average(scores)),
|
|
1130
1138
|
totalSaved: group.reduce((sum, e) => sum + (e.tokensSaved ?? 0), 0),
|
|
1131
|
-
totalCalls: group.reduce((sum, e) => sum + e.totalCalls, 0),
|
|
1139
|
+
totalCalls: group.reduce((sum, e) => sum + (e.totalCalls ?? 0), 0),
|
|
1132
1140
|
errorRate: group.length ? failures / group.length : 0
|
|
1133
1141
|
};
|
|
1134
1142
|
}).sort((a, b) => b.runs - a.runs || a.name.localeCompare(b.name));
|
|
@@ -1197,7 +1205,7 @@ function recentRunRows(entries) {
|
|
|
1197
1205
|
<td class="num">${escapeHtml(formatMs(durationOf(entry)))}</td>
|
|
1198
1206
|
<td class="num">${typeof entry.verificationScore === "number" ? formatNumber(entry.verificationScore) : "\u2014"}</td>
|
|
1199
1207
|
<td class="num">${typeof entry.tokensSaved === "number" ? formatNumber(entry.tokensSaved) : "\u2014"}</td>
|
|
1200
|
-
<td class="num">${formatNumber(entry.totalCalls)}</td>
|
|
1208
|
+
<td class="num">${formatNumber(entry.totalCalls ?? 0)}</td>
|
|
1201
1209
|
<td class="num">${typeof entry.extractionCacheHitRate === "number" ? formatPercent(entry.extractionCacheHitRate) : "\u2014"}</td>
|
|
1202
1210
|
<td class="mono small reason">${escapeHtml(entry.fallbackReason ?? entry.extractionCacheMissReason ?? "")}</td>
|
|
1203
1211
|
</tr>`).join(`
|
|
@@ -1210,8 +1218,8 @@ function buildMetricsReport(entries = readMetricsLog(100)) {
|
|
|
1210
1218
|
if (!entries.length)
|
|
1211
1219
|
return "No smart-compact metrics recorded yet.";
|
|
1212
1220
|
const summary = summarizeDashboard(entries);
|
|
1213
|
-
const byProfile = groupMetrics(entries, (e) => e.profile
|
|
1214
|
-
const byProvider = groupMetrics(entries, (e) => e.provider ?? e.model?.split("/")[0]
|
|
1221
|
+
const byProfile = groupMetrics(entries, (e) => e.profile);
|
|
1222
|
+
const byProvider = groupMetrics(entries, (e) => e.provider ?? e.model?.split("/")[0]);
|
|
1215
1223
|
const summarizeGroup = (group) => "- " + group.name + ": n=" + group.runs + ", avg=" + group.avgDuration + "ms, p95=" + group.p95Duration + "ms, score=" + group.avgScore + ", saved=" + group.totalSaved + "t, reliability=" + formatPercent(1 - group.errorRate);
|
|
1216
1224
|
const extractionCacheRuns = entries.filter((e) => typeof e.extractionCacheHitRate === "number");
|
|
1217
1225
|
const extractionCacheAvg = average(extractionCacheRuns.map((e) => e.extractionCacheHitRate ?? 0));
|
|
@@ -1240,8 +1248,8 @@ function writeMetricsDashboard(entries = readMetricsLog(200)) {
|
|
|
1240
1248
|
const summary = summarizeDashboard(entries);
|
|
1241
1249
|
const latest = entries[entries.length - 1];
|
|
1242
1250
|
const report = buildMetricsReport(entries);
|
|
1243
|
-
const profileGroups = groupMetrics(entries, (e) => e.profile
|
|
1244
|
-
const providerGroups = groupMetrics(entries, (e) => e.provider ?? e.model?.split("/")[0]
|
|
1251
|
+
const profileGroups = groupMetrics(entries, (e) => e.profile);
|
|
1252
|
+
const providerGroups = groupMetrics(entries, (e) => e.provider ?? e.model?.split("/")[0]);
|
|
1245
1253
|
const healthTone = summary.error + summary.timeout > 0 ? "warn" : "good";
|
|
1246
1254
|
const html = `<!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Smart Compact Metrics</title><style>${dashboardCss()}</style></head><body><main>
|
|
1247
1255
|
<header><div><div class="eyebrow">pi-smart-compact</div><h1>Operational Metrics</h1><div class="muted">Generated ${escapeHtml(new Date().toISOString())} \xB7 ${formatNumber(entries.length)} recent runs \xB7 local file dashboard</div></div><div>${badge(latest?.status)} ${latest ? `<span class="muted">latest ${escapeHtml(latest.profile ?? "unknown")}</span>` : ""}</div></header>
|
|
@@ -3154,12 +3162,18 @@ function verifySummary(summary, extraction) {
|
|
|
3154
3162
|
score -= 10;
|
|
3155
3163
|
}
|
|
3156
3164
|
}
|
|
3157
|
-
if (!lower.includes("## goal"))
|
|
3165
|
+
if (!lower.includes("## goal")) {
|
|
3166
|
+
gaps.push("Missing section: ## Goal");
|
|
3158
3167
|
score -= 5;
|
|
3159
|
-
|
|
3168
|
+
}
|
|
3169
|
+
if (!lower.includes("## progress")) {
|
|
3170
|
+
gaps.push("Missing section: ## Progress");
|
|
3160
3171
|
score -= 5;
|
|
3161
|
-
|
|
3172
|
+
}
|
|
3173
|
+
if (!lower.includes("## critical context")) {
|
|
3174
|
+
gaps.push("Missing section: ## Critical Context");
|
|
3162
3175
|
score -= 3;
|
|
3176
|
+
}
|
|
3163
3177
|
const summaryFileRefs = (summary.match(/[\w.\/-]+\.[\w]+/g) ?? []).filter((p) => p.includes("/") || p.match(/\.(ts|tsx|js|jsx|rs|py|go|java|rb|css|html|json|yaml|yml|toml|md|sh|sql)$/i));
|
|
3164
3178
|
const knownFiles = new Set([
|
|
3165
3179
|
...extraction.modifiedFiles.map((f) => f.path.toLowerCase()),
|
|
@@ -3209,7 +3223,8 @@ function verifySummary(summary, extraction) {
|
|
|
3209
3223
|
score -= 5;
|
|
3210
3224
|
}
|
|
3211
3225
|
}
|
|
3212
|
-
|
|
3226
|
+
const finalScore = Math.max(0, score);
|
|
3227
|
+
return { ok: gaps.length === 0 && finalScore >= 85, gaps, score: finalScore };
|
|
3213
3228
|
}
|
|
3214
3229
|
function patchDeterministic(summary, gaps, extraction) {
|
|
3215
3230
|
let patched = summary;
|
|
@@ -3217,47 +3232,75 @@ function patchDeterministic(summary, gaps, extraction) {
|
|
|
3217
3232
|
const errorGaps = gaps.filter((g) => g.startsWith("Missing error:"));
|
|
3218
3233
|
const constraintGaps = gaps.filter((g) => g.startsWith("Missing constraint:"));
|
|
3219
3234
|
const decisionGaps = gaps.filter((g) => g.startsWith("Missing decision:"));
|
|
3220
|
-
const
|
|
3221
|
-
const
|
|
3222
|
-
|
|
3235
|
+
const sectionGaps = gaps.filter((g) => g.startsWith("Missing section:"));
|
|
3236
|
+
const otherGaps = gaps.filter((g) => !g.startsWith("Missing modified file:") && !g.startsWith("Missing error:") && !g.startsWith("Missing constraint:") && !g.startsWith("Missing decision:") && !g.startsWith("Missing section:") && !g.startsWith("Potentially fabricated") && !g.startsWith("Inconsistency"));
|
|
3237
|
+
const escapeRe = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3238
|
+
const findOrCreateSectionInsert = (header, defaultBody = "") => {
|
|
3239
|
+
const re = new RegExp(escapeRe(header) + "\\s*\\n", "i");
|
|
3223
3240
|
const m = patched.match(re);
|
|
3224
|
-
|
|
3241
|
+
if (m?.index != null)
|
|
3242
|
+
return m.index + m[0].length;
|
|
3243
|
+
const prefix = patched.endsWith(`
|
|
3244
|
+
`) ? patched.endsWith(`
|
|
3245
|
+
|
|
3246
|
+
`) ? "" : `
|
|
3247
|
+
` : `
|
|
3248
|
+
|
|
3249
|
+
`;
|
|
3250
|
+
patched += prefix + header + `
|
|
3251
|
+
` + (defaultBody ? defaultBody.replace(/\n?$/, `
|
|
3252
|
+
`) : "");
|
|
3253
|
+
return patched.length;
|
|
3254
|
+
};
|
|
3255
|
+
const ensureMissingSection = (header) => {
|
|
3256
|
+
if (header === "## Goal") {
|
|
3257
|
+
findOrCreateSectionInsert(header, (extraction.mainGoal ?? "Continue the current coding task.") + `
|
|
3258
|
+
`);
|
|
3259
|
+
} else if (header === "## Progress") {
|
|
3260
|
+
findOrCreateSectionInsert(header, `### Done
|
|
3261
|
+
- See preceding summary.
|
|
3262
|
+
### In Progress
|
|
3263
|
+
- Continue from the latest user request.
|
|
3264
|
+
### Blocked
|
|
3265
|
+
- None recorded.
|
|
3266
|
+
`);
|
|
3267
|
+
} else if (header === "## Critical Context") {
|
|
3268
|
+
findOrCreateSectionInsert(header, `- None recorded.
|
|
3269
|
+
`);
|
|
3270
|
+
} else {
|
|
3271
|
+
findOrCreateSectionInsert(header);
|
|
3272
|
+
}
|
|
3225
3273
|
};
|
|
3274
|
+
for (const gap of sectionGaps) {
|
|
3275
|
+
ensureMissingSection(gap.replace("Missing section: ", ""));
|
|
3276
|
+
}
|
|
3226
3277
|
if (fileGaps.length > 0) {
|
|
3227
|
-
const insertPos =
|
|
3228
|
-
|
|
3229
|
-
const entries = fileGaps.map((g) => "- " + g.replace("Missing modified file: ", "")).join(`
|
|
3278
|
+
const insertPos = findOrCreateSectionInsert("## Files Modified");
|
|
3279
|
+
const entries = fileGaps.map((g) => "- " + g.replace("Missing modified file: ", "")).join(`
|
|
3230
3280
|
`) + `
|
|
3231
3281
|
`;
|
|
3232
|
-
|
|
3233
|
-
}
|
|
3282
|
+
patched = patched.slice(0, insertPos) + entries + patched.slice(insertPos);
|
|
3234
3283
|
}
|
|
3235
3284
|
if (errorGaps.length > 0) {
|
|
3236
|
-
const insertPos =
|
|
3237
|
-
|
|
3238
|
-
const entries = errorGaps.map((g) => "- " + g).join(`
|
|
3285
|
+
const insertPos = findOrCreateSectionInsert("## Critical Context");
|
|
3286
|
+
const entries = errorGaps.map((g) => "- " + g).join(`
|
|
3239
3287
|
`) + `
|
|
3240
3288
|
`;
|
|
3241
|
-
|
|
3242
|
-
}
|
|
3289
|
+
patched = patched.slice(0, insertPos) + entries + patched.slice(insertPos);
|
|
3243
3290
|
}
|
|
3244
3291
|
if (constraintGaps.length > 0) {
|
|
3245
|
-
const insertPos =
|
|
3246
|
-
|
|
3247
|
-
const entries = constraintGaps.map((g) => "- " + g).join(`
|
|
3292
|
+
const insertPos = findOrCreateSectionInsert("## Constraints & Preferences");
|
|
3293
|
+
const entries = constraintGaps.map((g) => "- " + g).join(`
|
|
3248
3294
|
`) + `
|
|
3249
3295
|
`;
|
|
3250
|
-
|
|
3251
|
-
}
|
|
3296
|
+
patched = patched.slice(0, insertPos) + entries + patched.slice(insertPos);
|
|
3252
3297
|
}
|
|
3253
3298
|
if (decisionGaps.length > 0) {
|
|
3254
|
-
const insertPos =
|
|
3255
|
-
|
|
3256
|
-
const entries = decisionGaps.map((g) => "- **" + g.replace("Missing decision: ", "") + "**").join(`
|
|
3299
|
+
const insertPos = findOrCreateSectionInsert("## Key Decisions");
|
|
3300
|
+
const entries = decisionGaps.map((g) => "- **" + g.replace("Missing decision: ", "") + "**").join(`
|
|
3257
3301
|
`) + `
|
|
3258
3302
|
`;
|
|
3259
|
-
|
|
3260
|
-
}
|
|
3303
|
+
patched = patched.slice(0, insertPos) + entries + patched.slice(insertPos);
|
|
3261
3304
|
}
|
|
3262
3305
|
if (otherGaps.length > 0) {
|
|
3263
3306
|
patched += `
|
|
@@ -3294,7 +3337,106 @@ Return the COMPLETE updated summary with missing items integrated. Keep the same
|
|
|
3294
3337
|
|
|
3295
3338
|
// src/ui/overlays.ts
|
|
3296
3339
|
import { DynamicBorder } from "@earendil-works/pi-coding-agent";
|
|
3297
|
-
import { Container, SelectList, Text } from "@earendil-works/pi-tui";
|
|
3340
|
+
import { Container, Key, matchesKey, SelectList, Text, truncateToWidth } from "@earendil-works/pi-tui";
|
|
3341
|
+
|
|
3342
|
+
// src/ui/dashboard-format.ts
|
|
3343
|
+
var DASHBOARD_PAGE_SIZE = 24;
|
|
3344
|
+
function metricDuration(entry) {
|
|
3345
|
+
return entry.durationMs ?? entry.phaseTimings?.reduce((sum, phase) => sum + phase.durationMs, 0) ?? 0;
|
|
3346
|
+
}
|
|
3347
|
+
function metricMs(ms) {
|
|
3348
|
+
if (!Number.isFinite(ms) || ms <= 0)
|
|
3349
|
+
return "0ms";
|
|
3350
|
+
return ms >= 1000 ? (ms / 1000).toFixed(ms >= 1e4 ? 0 : 1) + "s" : Math.round(ms) + "ms";
|
|
3351
|
+
}
|
|
3352
|
+
function clampRatio(value) {
|
|
3353
|
+
return Math.max(0, Math.min(1, value));
|
|
3354
|
+
}
|
|
3355
|
+
function metricPct(value) {
|
|
3356
|
+
return typeof value === "number" && Number.isFinite(value) ? Math.round(clampRatio(value) * 100) + "%" : "\u2014";
|
|
3357
|
+
}
|
|
3358
|
+
function metricNum(value) {
|
|
3359
|
+
return typeof value === "number" && Number.isFinite(value) ? value.toLocaleString() : "\u2014";
|
|
3360
|
+
}
|
|
3361
|
+
function metricScore(entry) {
|
|
3362
|
+
return typeof entry?.verificationScore === "number" && Number.isFinite(entry.verificationScore) ? entry.verificationScore + "/100" : "\u2014";
|
|
3363
|
+
}
|
|
3364
|
+
function formatMetricRun(entry, index) {
|
|
3365
|
+
const prefix = typeof index === "number" ? String(index).padStart(2, " ") + ". " : "";
|
|
3366
|
+
const time = entry.ts ? new Date(entry.ts).toLocaleString() : "unknown time";
|
|
3367
|
+
return prefix + time + " | " + (entry.profile ?? "?") + " | " + (entry.provider ?? entry.model ?? "?") + " | " + (entry.method ?? "?") + " | " + (entry.status ?? "?") + " | score " + metricScore(entry) + " | saved " + metricNum(entry.tokensSaved) + "t";
|
|
3368
|
+
}
|
|
3369
|
+
function formatMetricRunCompact(entry) {
|
|
3370
|
+
return "score " + metricScore(entry) + " \u2022 saved " + metricNum(entry.tokensSaved) + "t \u2022 " + (entry.status ?? "?") + " \u2022 " + (entry.profile ?? "?") + " / " + (entry.provider ?? entry.model ?? "?");
|
|
3371
|
+
}
|
|
3372
|
+
function formatPhaseTiming(phase, total) {
|
|
3373
|
+
const share = total > 0 ? Math.round(phase.durationMs / total * 100) : 0;
|
|
3374
|
+
return "- " + phase.phase + ": " + metricMs(phase.durationMs) + " (" + share + "%)";
|
|
3375
|
+
}
|
|
3376
|
+
function formatRunDetails(entry, title) {
|
|
3377
|
+
if (!entry)
|
|
3378
|
+
return [title, "", "No run recorded yet."];
|
|
3379
|
+
const totalDuration = metricDuration(entry);
|
|
3380
|
+
const lines = [
|
|
3381
|
+
title,
|
|
3382
|
+
"",
|
|
3383
|
+
"Session: " + entry.sessionId,
|
|
3384
|
+
"Time: " + (entry.ts ? new Date(entry.ts).toLocaleString() : "unknown"),
|
|
3385
|
+
"Status: " + (entry.status ?? "unknown") + " | run: " + (entry.runType ?? "?") + " | profile: " + (entry.profile ?? "?"),
|
|
3386
|
+
"Provider/model: " + (entry.provider ?? "?") + " / " + (entry.model ?? "?"),
|
|
3387
|
+
"Method: " + (entry.method ?? "?") + " | duration: " + metricMs(totalDuration),
|
|
3388
|
+
"Quality: " + metricScore(entry) + " | gaps: " + metricNum(entry.verificationGaps),
|
|
3389
|
+
"Tokens: before " + metricNum(entry.tokensBefore) + "t | saved " + metricNum(entry.tokensSaved) + "t | prune saved " + metricNum(entry.pruneSavedTokens) + "t",
|
|
3390
|
+
"LLM: " + metricNum(entry.totalCalls) + " calls | input " + metricNum(entry.totalInput) + "t | output " + metricNum(entry.totalOutput) + "t | provider cache " + metricPct(entry.cacheHitRate),
|
|
3391
|
+
"Extraction cache: " + metricNum(entry.extractionCacheHits) + " hit / " + metricNum(entry.extractionCacheMisses) + " miss | rate " + metricPct(entry.extractionCacheHitRate),
|
|
3392
|
+
"Context: " + metricNum(entry.contextPercent) + "% | tool share: " + metricNum(entry.toolPercent) + "% | chunks: " + metricNum(entry.chunkCount)
|
|
3393
|
+
];
|
|
3394
|
+
if (entry.extractionCacheMissReason)
|
|
3395
|
+
lines.push("Extraction miss reason: " + entry.extractionCacheMissReason);
|
|
3396
|
+
if (entry.fallbackReason)
|
|
3397
|
+
lines.push("Reason: " + entry.fallbackReason);
|
|
3398
|
+
if (entry.phaseTimings?.length) {
|
|
3399
|
+
lines.push("", "Phase timings:");
|
|
3400
|
+
lines.push(...entry.phaseTimings.map((phase) => formatPhaseTiming(phase, totalDuration)));
|
|
3401
|
+
}
|
|
3402
|
+
return lines;
|
|
3403
|
+
}
|
|
3404
|
+
function formatCurrentSession(entries, currentSessionId) {
|
|
3405
|
+
if (!currentSessionId || currentSessionId === "unknown")
|
|
3406
|
+
return ["Current session", "", "Session id is not available from Pi context."];
|
|
3407
|
+
const runs = entries.filter((entry) => entry.sessionId === currentSessionId);
|
|
3408
|
+
if (!runs.length)
|
|
3409
|
+
return ["Current session", "", "Session: " + currentSessionId, "No smart-compact metrics recorded for this session yet."];
|
|
3410
|
+
const success = runs.filter((entry) => entry.status === "success").length;
|
|
3411
|
+
const latest = runs[runs.length - 1];
|
|
3412
|
+
const totalSaved = runs.reduce((sum, entry) => sum + (entry.tokensSaved ?? 0), 0);
|
|
3413
|
+
const avgScoreValues = runs.map((entry) => entry.verificationScore).filter((v) => typeof v === "number" && Number.isFinite(v));
|
|
3414
|
+
const avgScore = avgScoreValues.length ? Math.round(avgScoreValues.reduce((sum, value) => sum + value, 0) / avgScoreValues.length) : 0;
|
|
3415
|
+
return [
|
|
3416
|
+
"Current session",
|
|
3417
|
+
"",
|
|
3418
|
+
"Session: " + currentSessionId,
|
|
3419
|
+
"Runs: " + runs.length + " | success " + success + " | total saved " + totalSaved.toLocaleString() + "t | avg score " + (avgScore || "\u2014"),
|
|
3420
|
+
"Latest: " + formatMetricRun(latest),
|
|
3421
|
+
"",
|
|
3422
|
+
"Runs in this session:",
|
|
3423
|
+
...runs.slice(-20).reverse().map((entry, i) => formatMetricRun(entry, i + 1))
|
|
3424
|
+
];
|
|
3425
|
+
}
|
|
3426
|
+
function formatRecentRuns(entries) {
|
|
3427
|
+
if (!entries.length)
|
|
3428
|
+
return ["Recent runs", "", "No smart-compact metrics recorded yet."];
|
|
3429
|
+
return [
|
|
3430
|
+
"Recent runs",
|
|
3431
|
+
"",
|
|
3432
|
+
...entries.slice(-30).reverse().map((entry, i) => formatMetricRun(entry, i + 1))
|
|
3433
|
+
];
|
|
3434
|
+
}
|
|
3435
|
+
function isDashboardTitleLine(line) {
|
|
3436
|
+
return line.startsWith("#") || line === "Latest run details" || line === "Current session" || line === "Recent runs" || line === "Phase timings:" || line === "Runs in this session:";
|
|
3437
|
+
}
|
|
3438
|
+
|
|
3439
|
+
// src/ui/overlays.ts
|
|
3298
3440
|
import path8 from "path";
|
|
3299
3441
|
function renderContextBar(theme, pct, tokens, barLen = 24) {
|
|
3300
3442
|
const clamped = Math.min(Math.max(pct, 0), 100);
|
|
@@ -3443,8 +3585,10 @@ async function showResultScreen(ctx, details, extraction) {
|
|
|
3443
3585
|
if (ms.totalCalls > 0) {
|
|
3444
3586
|
const providerCachePct = Math.round(ms.cacheHitRate * 100);
|
|
3445
3587
|
const extractionCachePct = Math.round(ecs.hitRate * 100);
|
|
3588
|
+
const promptInput = effectivePromptInputTokens(ms.totalInput, ms.totalCacheHit);
|
|
3589
|
+
const inputLabel = ms.totalCacheHit > 0 ? promptInput.toLocaleString() + "t prompt (" + ms.totalInput.toLocaleString() + "t new, " + ms.totalCacheHit.toLocaleString() + "t cached)" : ms.totalInput.toLocaleString() + "t in";
|
|
3446
3590
|
const cacheColor = extractionCachePct >= 50 ? "success" : extractionCachePct >= 20 ? "warning" : "dim";
|
|
3447
|
-
c.addChild(new Text(theme.fg("dim", " LLM: ") + theme.fg("text", ms.totalCalls + " calls") + theme.fg("dim", " \u2022 ") + theme.fg("text",
|
|
3591
|
+
c.addChild(new Text(theme.fg("dim", " LLM: ") + theme.fg("text", ms.totalCalls + " calls") + theme.fg("dim", " \u2022 ") + theme.fg("text", inputLabel) + theme.fg("dim", " \u2022 ") + theme.fg("dim", providerCachePct + "% provider cache") + theme.fg("dim", " \u2022 ") + theme.fg(cacheColor, extractionCachePct + "% extraction cache") + theme.fg("dim", " \u2022 ") + theme.fg("dim", ms.avgLatency + "ms avg"), 0, 0));
|
|
3448
3592
|
}
|
|
3449
3593
|
const modFiles = details.modifiedFiles;
|
|
3450
3594
|
const errCount = extraction.errors.length;
|
|
@@ -3524,6 +3668,116 @@ async function showResultScreen(ctx, details, extraction) {
|
|
|
3524
3668
|
};
|
|
3525
3669
|
}, { overlay: true, overlayOptions: { width: "70%", anchor: "center", maxHeight: "80%" } });
|
|
3526
3670
|
}
|
|
3671
|
+
async function showMetricsDashboardUI(ctx, opts) {
|
|
3672
|
+
const entries = opts.entries;
|
|
3673
|
+
const latest = entries[entries.length - 1];
|
|
3674
|
+
const currentRuns = opts.currentSessionId ? entries.filter((entry) => entry.sessionId === opts.currentSessionId) : [];
|
|
3675
|
+
const menuItems = [
|
|
3676
|
+
{ view: "overview", label: "Overview report", desc: entries.length + " recent run(s), profile/provider comparison" },
|
|
3677
|
+
{ view: "latest", label: "Latest run details", desc: latest ? formatMetricRunCompact(latest) : "No run recorded yet" },
|
|
3678
|
+
{ view: "session", label: "Current session", desc: (opts.currentSessionId ?? "unknown") + " \u2014 " + currentRuns.length + " run(s)" },
|
|
3679
|
+
{ view: "recent", label: "Recent runs", desc: "Last " + Math.min(entries.length, 30) + " run(s)" },
|
|
3680
|
+
{ action: "html", label: "Write HTML dashboard", desc: "Generate ~/.pi/agent/.cache/smart-compact-report.html" }
|
|
3681
|
+
];
|
|
3682
|
+
return await ctx.ui.custom((tui, theme, keybindings, done) => {
|
|
3683
|
+
let view = "menu";
|
|
3684
|
+
let selected = 0;
|
|
3685
|
+
let scroll = 0;
|
|
3686
|
+
const pageLines = () => {
|
|
3687
|
+
if (view === "overview")
|
|
3688
|
+
return opts.report.split(`
|
|
3689
|
+
`);
|
|
3690
|
+
if (view === "latest")
|
|
3691
|
+
return formatRunDetails(latest, "Latest run details");
|
|
3692
|
+
if (view === "session")
|
|
3693
|
+
return formatCurrentSession(entries, opts.currentSessionId);
|
|
3694
|
+
if (view === "recent")
|
|
3695
|
+
return formatRecentRuns(entries);
|
|
3696
|
+
return [];
|
|
3697
|
+
};
|
|
3698
|
+
const resetPage = (nextView) => {
|
|
3699
|
+
view = nextView;
|
|
3700
|
+
scroll = 0;
|
|
3701
|
+
};
|
|
3702
|
+
const renderHeader = (width) => [
|
|
3703
|
+
truncateToWidth(theme.fg("accent", theme.bold(" \uD83D\uDCCA Smart Compact Dashboard")) + theme.fg("dim", " " + entries.length + " recorded run(s)"), width),
|
|
3704
|
+
truncateToWidth(theme.fg("dim", " session: " + (opts.currentSessionId ?? "unknown")) + theme.fg("dim", latest ? " \u2022 latest score " + metricScore(latest) : ""), width),
|
|
3705
|
+
truncateToWidth(theme.fg("borderMuted", "\u2500".repeat(Math.max(0, width))), width)
|
|
3706
|
+
];
|
|
3707
|
+
return {
|
|
3708
|
+
render: (width) => {
|
|
3709
|
+
const lines = renderHeader(width);
|
|
3710
|
+
if (view === "menu") {
|
|
3711
|
+
lines.push(truncateToWidth(theme.fg("text", " Choose what to inspect:"), width), "");
|
|
3712
|
+
for (let i = 0;i < menuItems.length; i++) {
|
|
3713
|
+
const item = menuItems[i];
|
|
3714
|
+
const active = i === selected;
|
|
3715
|
+
const prefix = active ? " \u203A " : " ";
|
|
3716
|
+
const label = active ? theme.fg("accent", theme.bold(item.label)) : theme.fg("text", item.label);
|
|
3717
|
+
lines.push(truncateToWidth(prefix + label, width));
|
|
3718
|
+
lines.push(truncateToWidth(" " + theme.fg(active ? "muted" : "dim", item.desc), width));
|
|
3719
|
+
}
|
|
3720
|
+
lines.push("", truncateToWidth(theme.fg("dim", " \u2191\u2193 navigate \u2022 enter open \u2022 esc/q close"), width));
|
|
3721
|
+
return lines;
|
|
3722
|
+
}
|
|
3723
|
+
const content = pageLines();
|
|
3724
|
+
const available = DASHBOARD_PAGE_SIZE;
|
|
3725
|
+
const maxScroll = Math.max(0, content.length - available);
|
|
3726
|
+
if (scroll > maxScroll)
|
|
3727
|
+
scroll = maxScroll;
|
|
3728
|
+
for (const line of content.slice(scroll, scroll + available)) {
|
|
3729
|
+
const styled = isDashboardTitleLine(line) ? theme.fg("accent", theme.bold(line)) : line.startsWith("-") ? theme.fg("dim", line) : theme.fg("text", line);
|
|
3730
|
+
lines.push(truncateToWidth(" " + styled, width));
|
|
3731
|
+
}
|
|
3732
|
+
if (content.length > available) {
|
|
3733
|
+
lines.push(truncateToWidth(theme.fg("dim", " showing " + (scroll + 1) + "-" + Math.min(content.length, scroll + available) + " of " + content.length), width));
|
|
3734
|
+
}
|
|
3735
|
+
lines.push("", truncateToWidth(theme.fg("dim", " \u2191\u2193 scroll \u2022 pgup/pgdn page \u2022 home/end jump \u2022 b back \u2022 esc/q close"), width));
|
|
3736
|
+
return lines;
|
|
3737
|
+
},
|
|
3738
|
+
invalidate: () => {},
|
|
3739
|
+
handleInput: (data) => {
|
|
3740
|
+
if (keybindings.matches(data, "tui.select.cancel") || data === "q") {
|
|
3741
|
+
done(null);
|
|
3742
|
+
return;
|
|
3743
|
+
}
|
|
3744
|
+
if (view === "menu") {
|
|
3745
|
+
if (keybindings.matches(data, "tui.select.up"))
|
|
3746
|
+
selected = Math.max(0, selected - 1);
|
|
3747
|
+
else if (keybindings.matches(data, "tui.select.down"))
|
|
3748
|
+
selected = Math.min(menuItems.length - 1, selected + 1);
|
|
3749
|
+
else if (keybindings.matches(data, "tui.select.confirm")) {
|
|
3750
|
+
const item = menuItems[selected];
|
|
3751
|
+
if (item.action) {
|
|
3752
|
+
done(item.action);
|
|
3753
|
+
return;
|
|
3754
|
+
}
|
|
3755
|
+
if (item.view)
|
|
3756
|
+
resetPage(item.view);
|
|
3757
|
+
}
|
|
3758
|
+
} else {
|
|
3759
|
+
const content = pageLines();
|
|
3760
|
+
const maxScroll = Math.max(0, content.length - DASHBOARD_PAGE_SIZE);
|
|
3761
|
+
if (data === "b" || matchesKey(data, Key.left))
|
|
3762
|
+
resetPage("menu");
|
|
3763
|
+
else if (matchesKey(data, Key.home))
|
|
3764
|
+
scroll = 0;
|
|
3765
|
+
else if (matchesKey(data, Key.end))
|
|
3766
|
+
scroll = maxScroll;
|
|
3767
|
+
else if (keybindings.matches(data, "tui.select.pageUp"))
|
|
3768
|
+
scroll = Math.max(0, scroll - DASHBOARD_PAGE_SIZE);
|
|
3769
|
+
else if (keybindings.matches(data, "tui.select.pageDown"))
|
|
3770
|
+
scroll = Math.min(maxScroll, scroll + DASHBOARD_PAGE_SIZE);
|
|
3771
|
+
else if (keybindings.matches(data, "tui.select.up"))
|
|
3772
|
+
scroll = Math.max(0, scroll - 1);
|
|
3773
|
+
else if (keybindings.matches(data, "tui.select.down"))
|
|
3774
|
+
scroll = Math.min(maxScroll, scroll + 1);
|
|
3775
|
+
}
|
|
3776
|
+
tui.requestRender();
|
|
3777
|
+
}
|
|
3778
|
+
};
|
|
3779
|
+
}, { overlay: true, overlayOptions: { width: "80%", anchor: "center", maxHeight: "85%" } });
|
|
3780
|
+
}
|
|
3527
3781
|
async function showCompactUI(ctx, opts) {
|
|
3528
3782
|
const selectedModel = await selectModel(ctx, opts);
|
|
3529
3783
|
if (!selectedModel)
|
|
@@ -4007,7 +4261,9 @@ async function runSmartCompact(opts) {
|
|
|
4007
4261
|
if (ms.totalCalls > 0) {
|
|
4008
4262
|
const providerCacheRate = Math.round(ms.cacheHitRate * 100);
|
|
4009
4263
|
const extractionCacheRate = Math.round(ecs.hitRate * 100);
|
|
4010
|
-
|
|
4264
|
+
const promptInput = effectivePromptInputTokens(ms.totalInput, ms.totalCacheHit);
|
|
4265
|
+
const inputLabel = ms.totalCacheHit > 0 ? promptInput + "t prompt (" + ms.totalInput + "t new, " + ms.totalCacheHit + "t cached)" : ms.totalInput + "t in";
|
|
4266
|
+
notify("Metrics: " + ms.totalCalls + " calls, " + inputLabel + ", " + ms.totalOutput + "t out, provider-cache " + providerCacheRate + "% (internal phases disabled), extraction-cache " + extractionCacheRate + "%, " + ms.avgLatency + "ms avg", "info");
|
|
4011
4267
|
}
|
|
4012
4268
|
if (!autoTriggered) {
|
|
4013
4269
|
try {
|
|
@@ -4106,12 +4362,21 @@ function smartCompactExtension(pi) {
|
|
|
4106
4362
|
const verbose = flags.includes("verbose") || flags.includes("debug");
|
|
4107
4363
|
const dryRun = flags.includes("dry-run");
|
|
4108
4364
|
if (flags.includes("metrics") || flags.includes("dashboard")) {
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
|
|
4365
|
+
if (flags.includes("dashboard")) {
|
|
4366
|
+
const entries = readMetricsLog(200);
|
|
4367
|
+
const sessionId = ctx.sessionManager.getSessionId?.() ?? "unknown";
|
|
4368
|
+
const action = await showMetricsDashboardUI(ctx, {
|
|
4369
|
+
entries,
|
|
4370
|
+
currentSessionId: sessionId,
|
|
4371
|
+
report: buildMetricsReport(entries)
|
|
4372
|
+
});
|
|
4373
|
+
if (action === "html") {
|
|
4374
|
+
const fp = writeMetricsDashboard(entries);
|
|
4375
|
+
ctx.ui.notify(fp ? "Dashboard written: " + fp : "Dashboard could not be written", fp ? "info" : "error");
|
|
4376
|
+
}
|
|
4377
|
+
} else {
|
|
4378
|
+
ctx.ui.notify(buildMetricsReport(), "info");
|
|
4379
|
+
}
|
|
4115
4380
|
return;
|
|
4116
4381
|
}
|
|
4117
4382
|
const modelArg = tokens.find((t) => t.includes("/"));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../src/phases/verify.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,KAAK,EAAE,oBAAoB,EAAE,kBAAkB,EAAqB,MAAM,aAAa,CAAC;AAK/F,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,oBAAoB,GAAG,kBAAkB,
|
|
1
|
+
{"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../src/phases/verify.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,KAAK,EAAE,oBAAoB,EAAE,kBAAkB,EAAqB,MAAM,aAAa,CAAC;AAK/F,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,oBAAoB,GAAG,kBAAkB,CAyGnG;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,UAAU,EAAE,oBAAoB,GAAG,MAAM,CAiF5G;AAED,wBAAsB,YAAY,CAChC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAC/B,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,EAAE,MAAM,CAAC,EAAE,WAAW,GAClG,OAAO,CAAC,MAAM,CAAC,CAcjB"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { CompactMetricsEntry } from "../types.ts";
|
|
2
|
+
export declare const DASHBOARD_PAGE_SIZE = 24;
|
|
3
|
+
export declare function metricDuration(entry: CompactMetricsEntry): number;
|
|
4
|
+
export declare function metricMs(ms: number): string;
|
|
5
|
+
export declare function metricPct(value: number | undefined): string;
|
|
6
|
+
export declare function metricNum(value: number | undefined): string;
|
|
7
|
+
export declare function metricScore(entry: CompactMetricsEntry | undefined): string;
|
|
8
|
+
export declare function formatMetricRun(entry: CompactMetricsEntry, index?: number): string;
|
|
9
|
+
export declare function formatMetricRunCompact(entry: CompactMetricsEntry): string;
|
|
10
|
+
export declare function formatRunDetails(entry: CompactMetricsEntry | undefined, title: string): string[];
|
|
11
|
+
export declare function formatCurrentSession(entries: CompactMetricsEntry[], currentSessionId: string | undefined): string[];
|
|
12
|
+
export declare function formatRecentRuns(entries: CompactMetricsEntry[]): string[];
|
|
13
|
+
export declare function isDashboardTitleLine(line: string): boolean;
|
|
14
|
+
//# sourceMappingURL=dashboard-format.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard-format.d.ts","sourceRoot":"","sources":["../../src/ui/dashboard-format.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAuB,MAAM,aAAa,CAAC;AAE5E,eAAO,MAAM,mBAAmB,KAAK,CAAC;AAEtC,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,GAAG,MAAM,CAEjE;AAED,wBAAgB,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAG3C;AAMD,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAE3D;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAE3D;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,mBAAmB,GAAG,SAAS,GAAG,MAAM,CAE1E;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,mBAAmB,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAIlF;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,mBAAmB,GAAG,MAAM,CAEzE;AAOD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,mBAAmB,GAAG,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAwBhG;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,mBAAmB,EAAE,EAAE,gBAAgB,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,EAAE,CAmBnH;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,mBAAmB,EAAE,GAAG,MAAM,EAAE,CAOzE;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE1D"}
|
package/dist/ui/overlays.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* TUI overlays: model/profile selection, progress, result screen.
|
|
3
3
|
*/
|
|
4
4
|
import type { ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
|
|
5
|
-
import type { CompressionProfile, ModelOption, ProgressState, SmartCompactDetails, StructuredExtraction } from "../types.ts";
|
|
5
|
+
import type { CompactMetricsEntry, CompressionProfile, ModelOption, ProgressState, SmartCompactDetails, StructuredExtraction } from "../types.ts";
|
|
6
6
|
export declare function renderContextBar(theme: any, pct: number, tokens: number, barLen?: number): string;
|
|
7
7
|
export declare function renderTokenBar(theme: any, before: number, after: number, label: string, barLen?: number): string;
|
|
8
8
|
export declare function selectModel(ctx: ExtensionCommandContext, opts: {
|
|
@@ -17,6 +17,12 @@ export declare function selectProfile(ctx: ExtensionCommandContext, selectedMode
|
|
|
17
17
|
}): Promise<CompressionProfile | null>;
|
|
18
18
|
export declare function showProgressOverlay(ctx: ExtensionCommandContext, state: ProgressState): void;
|
|
19
19
|
export declare function showResultScreen(ctx: ExtensionCommandContext, details: SmartCompactDetails, extraction: StructuredExtraction): Promise<void>;
|
|
20
|
+
type DashboardAction = "html" | null;
|
|
21
|
+
export declare function showMetricsDashboardUI(ctx: ExtensionCommandContext, opts: {
|
|
22
|
+
entries: CompactMetricsEntry[];
|
|
23
|
+
currentSessionId?: string;
|
|
24
|
+
report: string;
|
|
25
|
+
}): Promise<DashboardAction>;
|
|
20
26
|
export declare function showCompactUI(ctx: ExtensionCommandContext, opts: {
|
|
21
27
|
contextTokens: number;
|
|
22
28
|
contextPercent: number;
|
|
@@ -26,4 +32,5 @@ export declare function showCompactUI(ctx: ExtensionCommandContext, opts: {
|
|
|
26
32
|
model: ModelOption;
|
|
27
33
|
profile: CompressionProfile;
|
|
28
34
|
} | null>;
|
|
35
|
+
export {};
|
|
29
36
|
//# sourceMappingURL=overlays.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"overlays.d.ts","sourceRoot":"","sources":["../../src/ui/overlays.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAI/E,OAAO,KAAK,EACV,kBAAkB,EAAE,WAAW,EAAE,aAAa,
|
|
1
|
+
{"version":3,"file":"overlays.d.ts","sourceRoot":"","sources":["../../src/ui/overlays.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAI/E,OAAO,KAAK,EACV,mBAAmB,EAAE,kBAAkB,EAAE,WAAW,EAAE,aAAa,EACnE,mBAAmB,EAAE,oBAAoB,EAC1C,MAAM,aAAa,CAAC;AAcrB,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,SAAK,GAAG,MAAM,CAS7F;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,SAAK,GAAG,MAAM,CAO5G;AAED,wBAAsB,WAAW,CAC/B,GAAG,EAAE,uBAAuB,EAC5B,IAAI,EAAE;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,iBAAiB,EAAE,MAAM,CAAA;CAAE,GACvG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CA8C7B;AAED,wBAAsB,aAAa,CACjC,GAAG,EAAE,uBAAuB,EAC5B,aAAa,EAAE,WAAW,EAC1B,IAAI,EAAE;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAE,GACtD,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CA4CpC;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,uBAAuB,EAAE,KAAK,EAAE,aAAa,GAAG,IAAI,CAM5F;AAED,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,uBAAuB,EAC5B,OAAO,EAAE,mBAAmB,EAC5B,UAAU,EAAE,oBAAoB,GAC/B,OAAO,CAAC,IAAI,CAAC,CA8Jf;AAGD,KAAK,eAAe,GAAG,MAAM,GAAG,IAAI,CAAC;AAErC,wBAAsB,sBAAsB,CAC1C,GAAG,EAAE,uBAAuB,EAC5B,IAAI,EAAE;IAAE,OAAO,EAAE,mBAAmB,EAAE,CAAC;IAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAClF,OAAO,CAAC,eAAe,CAAC,CA+F1B;AAED,wBAAsB,aAAa,CACjC,GAAG,EAAE,uBAAuB,EAC5B,IAAI,EAAE;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,iBAAiB,EAAE,MAAM,CAAA;CAAE,GACvG,OAAO,CAAC;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,OAAO,EAAE,kBAAkB,CAAA;CAAE,GAAG,IAAI,CAAC,CAMrE"}
|
package/dist/utils/cache.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ export declare function cacheOpts(opts: CacheAwareOptions, provider?: string, ph
|
|
|
11
11
|
export declare function resetMetrics(): void;
|
|
12
12
|
export declare function recordMetric(m: LLMCallMetric): void;
|
|
13
13
|
export declare function getMetrics(): LLMCallMetric[];
|
|
14
|
+
export declare function effectivePromptInputTokens(inputTokens: number, cacheHitTokens: number): number;
|
|
14
15
|
export declare function getMetricsSummary(): {
|
|
15
16
|
totalCalls: number;
|
|
16
17
|
totalInput: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/utils/cache.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,iBAAiB,EAAuB,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAGtJ,OAAO,EAAY,KAAK,KAAK,EAAE,KAAK,GAAG,EAAE,KAAK,gBAAgB,EAAE,KAAK,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAO5G,wBAAgB,mBAAmB,IAAI,MAAM,CAK5C;AAED,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C;AASD,wBAAgB,SAAS,CACvB,IAAI,EAAE,iBAAiB,EACvB,QAAQ,CAAC,EAAE,MAAM,EACjB,KAAK,CAAC,EAAE,aAAa,CAAC,OAAO,CAAC,GAC7B,iBAAiB,GAAG;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAY5C;AAKD,wBAAgB,YAAY,IAAI,IAAI,CAAyB;AAC7D,wBAAgB,YAAY,CAAC,CAAC,EAAE,aAAa,GAAG,IAAI,CAA4F;AAChJ,wBAAgB,UAAU,IAAI,aAAa,EAAE,CAA0B;AAEvE,wBAAgB,iBAAiB,IAAI;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,
|
|
1
|
+
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/utils/cache.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-smart-compact",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.13.0",
|
|
4
4
|
"description": "EESV smart compaction extension for Pi Coding Agent — deterministic extraction, exploration, synthesis, verification with redundancy pruning, project fingerprinting, and damage detection.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "./dist/index.js",
|