@planckspace/cli 0.1.0 → 0.2.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/README.md +24 -1
- package/dist/anomaly/constants.d.ts +13 -0
- package/dist/anomaly/constants.d.ts.map +1 -0
- package/dist/anomaly/constants.js +13 -0
- package/dist/anomaly/constants.js.map +1 -0
- package/dist/anomaly/detector.d.ts +12 -0
- package/dist/anomaly/detector.d.ts.map +1 -0
- package/dist/anomaly/detector.js +98 -0
- package/dist/anomaly/detector.js.map +1 -0
- package/dist/anomaly/types.d.ts +19 -0
- package/dist/anomaly/types.d.ts.map +1 -0
- package/dist/anomaly/types.js +2 -0
- package/dist/anomaly/types.js.map +1 -0
- package/dist/commands/budget.d.ts +26 -0
- package/dist/commands/budget.d.ts.map +1 -0
- package/dist/commands/budget.js +91 -0
- package/dist/commands/budget.js.map +1 -0
- package/dist/commands/config.d.ts +4 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +45 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/connect.d.ts +17 -0
- package/dist/commands/connect.d.ts.map +1 -0
- package/dist/commands/connect.js +191 -0
- package/dist/commands/connect.js.map +1 -0
- package/dist/commands/daemon.d.ts +8 -0
- package/dist/commands/daemon.d.ts.map +1 -0
- package/dist/commands/daemon.js +310 -0
- package/dist/commands/daemon.js.map +1 -0
- package/dist/commands/diagnose.d.ts +2 -0
- package/dist/commands/diagnose.d.ts.map +1 -0
- package/dist/commands/diagnose.js +81 -0
- package/dist/commands/diagnose.js.map +1 -0
- package/dist/commands/doctor.d.ts +2 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +67 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/export.d.ts +40 -0
- package/dist/commands/export.d.ts.map +1 -0
- package/dist/commands/export.js +184 -0
- package/dist/commands/export.js.map +1 -0
- package/dist/commands/init.d.ts +3 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +14 -1
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/insights.d.ts +2 -0
- package/dist/commands/insights.d.ts.map +1 -0
- package/dist/commands/insights.js +71 -0
- package/dist/commands/insights.js.map +1 -0
- package/dist/commands/inspect.d.ts +2 -0
- package/dist/commands/inspect.d.ts.map +1 -0
- package/dist/commands/inspect.js +81 -0
- package/dist/commands/inspect.js.map +1 -0
- package/dist/commands/integrations.d.ts +2 -0
- package/dist/commands/integrations.d.ts.map +1 -0
- package/dist/commands/integrations.js +46 -0
- package/dist/commands/integrations.js.map +1 -0
- package/dist/commands/login.d.ts +1 -1
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +45 -6
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/metrics.d.ts +6 -0
- package/dist/commands/metrics.d.ts.map +1 -0
- package/dist/commands/metrics.js +85 -0
- package/dist/commands/metrics.js.map +1 -0
- package/dist/commands/reconcile.d.ts +2 -0
- package/dist/commands/reconcile.d.ts.map +1 -0
- package/dist/commands/reconcile.js +63 -0
- package/dist/commands/reconcile.js.map +1 -0
- package/dist/commands/scan.d.ts.map +1 -1
- package/dist/commands/scan.js +53 -10
- package/dist/commands/scan.js.map +1 -1
- package/dist/commands/status.d.ts +1 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +84 -14
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/subscription.d.ts +15 -0
- package/dist/commands/subscription.d.ts.map +1 -0
- package/dist/commands/subscription.js +62 -0
- package/dist/commands/subscription.js.map +1 -0
- package/dist/commands/sync.d.ts +1 -1
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +77 -10
- package/dist/commands/sync.js.map +1 -1
- package/dist/commands/value.d.ts +5 -0
- package/dist/commands/value.d.ts.map +1 -0
- package/dist/commands/value.js +95 -0
- package/dist/commands/value.js.map +1 -0
- package/dist/config.d.ts +28 -3
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +9 -1
- package/dist/config.js.map +1 -1
- package/dist/correlate.d.ts +7 -0
- package/dist/correlate.d.ts.map +1 -1
- package/dist/correlate.js +102 -15
- package/dist/correlate.js.map +1 -1
- package/dist/daemon/daemon.d.ts +2 -0
- package/dist/daemon/daemon.d.ts.map +1 -0
- package/dist/daemon/daemon.js +188 -0
- package/dist/daemon/daemon.js.map +1 -0
- package/dist/daemon/daemonState.d.ts +25 -0
- package/dist/daemon/daemonState.d.ts.map +1 -0
- package/dist/daemon/daemonState.js +82 -0
- package/dist/daemon/daemonState.js.map +1 -0
- package/dist/daemon/logger.d.ts +7 -0
- package/dist/daemon/logger.d.ts.map +1 -0
- package/dist/daemon/logger.js +61 -0
- package/dist/daemon/logger.js.map +1 -0
- package/dist/daemon/syncLoop.d.ts +38 -0
- package/dist/daemon/syncLoop.d.ts.map +1 -0
- package/dist/daemon/syncLoop.js +119 -0
- package/dist/daemon/syncLoop.js.map +1 -0
- package/dist/daemon/watcher.d.ts +26 -0
- package/dist/daemon/watcher.d.ts.map +1 -0
- package/dist/daemon/watcher.js +187 -0
- package/dist/daemon/watcher.js.map +1 -0
- package/dist/db/store.d.ts +123 -2
- package/dist/db/store.d.ts.map +1 -1
- package/dist/db/store.js +397 -11
- package/dist/db/store.js.map +1 -1
- package/dist/detectors/cache-gap.d.ts +3 -0
- package/dist/detectors/cache-gap.d.ts.map +1 -0
- package/dist/detectors/cache-gap.js +70 -0
- package/dist/detectors/cache-gap.js.map +1 -0
- package/dist/detectors/context-bloat.d.ts +3 -0
- package/dist/detectors/context-bloat.d.ts.map +1 -0
- package/dist/detectors/context-bloat.js +68 -0
- package/dist/detectors/context-bloat.js.map +1 -0
- package/dist/detectors/fileTokens.d.ts +3 -0
- package/dist/detectors/fileTokens.d.ts.map +1 -0
- package/dist/detectors/fileTokens.js +12 -0
- package/dist/detectors/fileTokens.js.map +1 -0
- package/dist/detectors/index.d.ts +20 -0
- package/dist/detectors/index.d.ts.map +1 -0
- package/dist/detectors/index.js +41 -0
- package/dist/detectors/index.js.map +1 -0
- package/dist/detectors/model-routing.d.ts +3 -0
- package/dist/detectors/model-routing.d.ts.map +1 -0
- package/dist/detectors/model-routing.js +71 -0
- package/dist/detectors/model-routing.js.map +1 -0
- package/dist/detectors/repeat-read.d.ts +3 -0
- package/dist/detectors/repeat-read.d.ts.map +1 -0
- package/dist/detectors/repeat-read.js +69 -0
- package/dist/detectors/repeat-read.js.map +1 -0
- package/dist/detectors/seat-efficiency.d.ts +4 -0
- package/dist/detectors/seat-efficiency.d.ts.map +1 -0
- package/dist/detectors/seat-efficiency.js +86 -0
- package/dist/detectors/seat-efficiency.js.map +1 -0
- package/dist/detectors/types.d.ts +46 -0
- package/dist/detectors/types.d.ts.map +1 -0
- package/dist/detectors/types.js +2 -0
- package/dist/detectors/types.js.map +1 -0
- package/dist/health.d.ts +59 -0
- package/dist/health.d.ts.map +1 -0
- package/dist/health.js +106 -0
- package/dist/health.js.map +1 -0
- package/dist/index.js +389 -5
- package/dist/index.js.map +1 -1
- package/dist/metrics.d.ts +29 -0
- package/dist/metrics.d.ts.map +1 -0
- package/dist/metrics.js +205 -0
- package/dist/metrics.js.map +1 -0
- package/dist/scrapers/claudeCode.d.ts +1 -0
- package/dist/scrapers/claudeCode.d.ts.map +1 -1
- package/dist/scrapers/claudeCode.js +43 -13
- package/dist/scrapers/claudeCode.js.map +1 -1
- package/dist/scrapers/cursor.d.ts +3 -2
- package/dist/scrapers/cursor.d.ts.map +1 -1
- package/dist/scrapers/cursor.js +56 -16
- package/dist/scrapers/cursor.js.map +1 -1
- package/dist/scrapers/jetbrains.d.ts +15 -0
- package/dist/scrapers/jetbrains.d.ts.map +1 -0
- package/dist/scrapers/jetbrains.js +232 -0
- package/dist/scrapers/jetbrains.js.map +1 -0
- package/dist/scrapers/types.d.ts +4 -1
- package/dist/scrapers/types.d.ts.map +1 -1
- package/dist/scrapers/windsurf.d.ts +3 -2
- package/dist/scrapers/windsurf.d.ts.map +1 -1
- package/dist/scrapers/windsurf.js +25 -9
- package/dist/scrapers/windsurf.js.map +1 -1
- package/dist/sync/payload.d.ts +4 -5
- package/dist/sync/payload.d.ts.map +1 -1
- package/dist/sync/payload.js +88 -7
- package/dist/sync/payload.js.map +1 -1
- package/dist/sync/syncEngine.d.ts +19 -3
- package/dist/sync/syncEngine.d.ts.map +1 -1
- package/dist/sync/syncEngine.js +116 -10
- package/dist/sync/syncEngine.js.map +1 -1
- package/install.sh +27 -10
- package/package.json +43 -42
- package/dist/__tests__/correlate.test.d.ts +0 -2
- package/dist/__tests__/correlate.test.d.ts.map +0 -1
- package/dist/__tests__/correlate.test.js +0 -204
- package/dist/__tests__/correlate.test.js.map +0 -1
- package/dist/scrapers/__tests__/claudeCode.test.d.ts +0 -2
- package/dist/scrapers/__tests__/claudeCode.test.d.ts.map +0 -1
- package/dist/scrapers/__tests__/claudeCode.test.js +0 -115
- package/dist/scrapers/__tests__/claudeCode.test.js.map +0 -1
- package/dist/scrapers/__tests__/cursor.test.d.ts +0 -2
- package/dist/scrapers/__tests__/cursor.test.d.ts.map +0 -1
- package/dist/scrapers/__tests__/cursor.test.js +0 -173
- package/dist/scrapers/__tests__/cursor.test.js.map +0 -1
- package/dist/scrapers/__tests__/windsurf.test.d.ts +0 -2
- package/dist/scrapers/__tests__/windsurf.test.d.ts.map +0 -1
- package/dist/scrapers/__tests__/windsurf.test.js +0 -87
- package/dist/scrapers/__tests__/windsurf.test.js.map +0 -1
- package/dist/scripts/scanTest.d.ts +0 -3
- package/dist/scripts/scanTest.d.ts.map +0 -1
- package/dist/scripts/scanTest.js +0 -146
- package/dist/scripts/scanTest.js.map +0 -1
- package/dist/sync/__tests__/payload.privacy.test.d.ts +0 -2
- package/dist/sync/__tests__/payload.privacy.test.d.ts.map +0 -1
- package/dist/sync/__tests__/payload.privacy.test.js +0 -100
- package/dist/sync/__tests__/payload.privacy.test.js.map +0 -1
package/dist/db/store.js
CHANGED
|
@@ -29,6 +29,9 @@ export function initDb(dbPath = DB_PATH) {
|
|
|
29
29
|
cacheReadTokens INTEGER NOT NULL DEFAULT 0,
|
|
30
30
|
cacheWriteTokens INTEGER NOT NULL DEFAULT 0,
|
|
31
31
|
costUsd REAL NOT NULL DEFAULT 0,
|
|
32
|
+
costType TEXT NOT NULL DEFAULT 'imputed',
|
|
33
|
+
subscriptionPlan TEXT,
|
|
34
|
+
unmatchedTurns INTEGER NOT NULL DEFAULT 0,
|
|
32
35
|
repoName TEXT,
|
|
33
36
|
gitBranch TEXT,
|
|
34
37
|
gitAuthorEmail TEXT,
|
|
@@ -37,7 +40,10 @@ export function initDb(dbPath = DB_PATH) {
|
|
|
37
40
|
filesTouchedCount INTEGER NOT NULL DEFAULT 0,
|
|
38
41
|
outcome TEXT NOT NULL DEFAULT 'unknown',
|
|
39
42
|
turnsJson TEXT NOT NULL DEFAULT '[]',
|
|
40
|
-
scrapedAt TEXT NOT NULL
|
|
43
|
+
scrapedAt TEXT NOT NULL,
|
|
44
|
+
mergedPrNumber INTEGER,
|
|
45
|
+
mergedAt TEXT,
|
|
46
|
+
timeToMergeMs INTEGER
|
|
41
47
|
);
|
|
42
48
|
|
|
43
49
|
CREATE TABLE IF NOT EXISTS sync_state (
|
|
@@ -50,14 +56,63 @@ export function initDb(dbPath = DB_PATH) {
|
|
|
50
56
|
key TEXT PRIMARY KEY,
|
|
51
57
|
value TEXT NOT NULL
|
|
52
58
|
);
|
|
59
|
+
|
|
60
|
+
CREATE TABLE IF NOT EXISTS insights (
|
|
61
|
+
id TEXT PRIMARY KEY,
|
|
62
|
+
detectorId TEXT NOT NULL,
|
|
63
|
+
repoName TEXT,
|
|
64
|
+
workspaceScope TEXT NOT NULL,
|
|
65
|
+
titleShort TEXT NOT NULL,
|
|
66
|
+
estimatedMonthlySavingsUsd REAL NOT NULL DEFAULT 0,
|
|
67
|
+
confidence TEXT NOT NULL,
|
|
68
|
+
evidenceJson TEXT NOT NULL,
|
|
69
|
+
manualFix TEXT NOT NULL,
|
|
70
|
+
createdAt TEXT NOT NULL,
|
|
71
|
+
syncedAt TEXT
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
CREATE TABLE IF NOT EXISTS file_offsets (
|
|
75
|
+
filePath TEXT PRIMARY KEY,
|
|
76
|
+
byteOffset INTEGER NOT NULL DEFAULT 0,
|
|
77
|
+
updatedAt TEXT NOT NULL
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
CREATE TABLE IF NOT EXISTS anomalies (
|
|
81
|
+
id TEXT PRIMARY KEY,
|
|
82
|
+
type TEXT NOT NULL,
|
|
83
|
+
repoName TEXT,
|
|
84
|
+
sessionId TEXT,
|
|
85
|
+
costUsd REAL NOT NULL,
|
|
86
|
+
baselineUsd REAL NOT NULL,
|
|
87
|
+
ratio REAL NOT NULL,
|
|
88
|
+
detectedAt TEXT NOT NULL,
|
|
89
|
+
syncedAt TEXT
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
CREATE TABLE IF NOT EXISTS connection_state (
|
|
93
|
+
key TEXT PRIMARY KEY,
|
|
94
|
+
value TEXT NOT NULL
|
|
95
|
+
);
|
|
53
96
|
`);
|
|
54
|
-
//
|
|
97
|
+
// Idempotent migrations for columns added after initial schema.
|
|
55
98
|
const columns = db
|
|
56
99
|
.prepare("PRAGMA table_info(sessions)")
|
|
57
100
|
.all();
|
|
58
|
-
|
|
101
|
+
const has = (col) => columns.some((c) => c.name === col);
|
|
102
|
+
if (!has("gitAuthorEmail"))
|
|
59
103
|
db.exec("ALTER TABLE sessions ADD COLUMN gitAuthorEmail TEXT");
|
|
60
|
-
|
|
104
|
+
if (!has("costType"))
|
|
105
|
+
db.exec("ALTER TABLE sessions ADD COLUMN costType TEXT NOT NULL DEFAULT 'imputed'");
|
|
106
|
+
if (!has("subscriptionPlan"))
|
|
107
|
+
db.exec("ALTER TABLE sessions ADD COLUMN subscriptionPlan TEXT");
|
|
108
|
+
if (!has("unmatchedTurns"))
|
|
109
|
+
db.exec("ALTER TABLE sessions ADD COLUMN unmatchedTurns INTEGER NOT NULL DEFAULT 0");
|
|
110
|
+
if (!has("mergedPrNumber"))
|
|
111
|
+
db.exec("ALTER TABLE sessions ADD COLUMN mergedPrNumber INTEGER");
|
|
112
|
+
if (!has("mergedAt"))
|
|
113
|
+
db.exec("ALTER TABLE sessions ADD COLUMN mergedAt TEXT");
|
|
114
|
+
if (!has("timeToMergeMs"))
|
|
115
|
+
db.exec("ALTER TABLE sessions ADD COLUMN timeToMergeMs INTEGER");
|
|
61
116
|
_db = db;
|
|
62
117
|
}
|
|
63
118
|
/** Close the database handle (mainly for tests; releases the file lock on Windows). */
|
|
@@ -72,16 +127,18 @@ export function upsertSessions(sessions) {
|
|
|
72
127
|
let added = 0;
|
|
73
128
|
let updated = 0;
|
|
74
129
|
const now = new Date().toISOString();
|
|
75
|
-
const checkStmt = db.prepare("SELECT id FROM sessions WHERE id = ?");
|
|
130
|
+
const checkStmt = db.prepare("SELECT id, turnCount FROM sessions WHERE id = ?");
|
|
76
131
|
const upsertStmt = db.prepare(`
|
|
77
132
|
INSERT INTO sessions (
|
|
78
133
|
id, tool, model, startedAt, endedAt,
|
|
79
134
|
inputTokens, outputTokens, cacheReadTokens, cacheWriteTokens, costUsd,
|
|
135
|
+
costType, subscriptionPlan, unmatchedTurns,
|
|
80
136
|
repoName, gitBranch, workingDir, turnCount, filesTouchedCount,
|
|
81
137
|
outcome, turnsJson, scrapedAt
|
|
82
138
|
) VALUES (
|
|
83
139
|
?, ?, ?, ?, ?,
|
|
84
140
|
?, ?, ?, ?, ?,
|
|
141
|
+
?, ?, ?,
|
|
85
142
|
?, ?, ?, ?, ?,
|
|
86
143
|
'unknown', ?, ?
|
|
87
144
|
)
|
|
@@ -95,6 +152,9 @@ export function upsertSessions(sessions) {
|
|
|
95
152
|
cacheReadTokens = excluded.cacheReadTokens,
|
|
96
153
|
cacheWriteTokens = excluded.cacheWriteTokens,
|
|
97
154
|
costUsd = excluded.costUsd,
|
|
155
|
+
costType = excluded.costType,
|
|
156
|
+
subscriptionPlan = excluded.subscriptionPlan,
|
|
157
|
+
unmatchedTurns = excluded.unmatchedTurns,
|
|
98
158
|
repoName = excluded.repoName,
|
|
99
159
|
gitBranch = excluded.gitBranch,
|
|
100
160
|
workingDir = excluded.workingDir,
|
|
@@ -103,9 +163,14 @@ export function upsertSessions(sessions) {
|
|
|
103
163
|
turnsJson = excluded.turnsJson,
|
|
104
164
|
scrapedAt = excluded.scrapedAt
|
|
105
165
|
`);
|
|
106
|
-
|
|
166
|
+
// Insert sync_state for new sessions; for updated sessions with more turns,
|
|
167
|
+
// clear syncedAt so the fresh data is re-queued on the next sync cycle.
|
|
168
|
+
const syncInsertStmt = db.prepare(`
|
|
107
169
|
INSERT OR IGNORE INTO sync_state (sessionId, syncedAt, lastError)
|
|
108
170
|
VALUES (?, NULL, NULL)
|
|
171
|
+
`);
|
|
172
|
+
const syncResetStmt = db.prepare(`
|
|
173
|
+
UPDATE sync_state SET syncedAt = NULL WHERE sessionId = ?
|
|
109
174
|
`);
|
|
110
175
|
const run = db.transaction(() => {
|
|
111
176
|
for (const session of sessions) {
|
|
@@ -116,8 +181,14 @@ export function upsertSessions(sessions) {
|
|
|
116
181
|
else {
|
|
117
182
|
added++;
|
|
118
183
|
}
|
|
119
|
-
upsertStmt.run(session.sessionId, session.tool, session.model, session.startedAt, session.endedAt, session.inputTokens, session.outputTokens, session.cacheReadTokens, session.cacheWriteTokens, session.costUsd, session.repoName, session.gitBranch, session.workingDir, session.turnCount, session.filesTouchedCount, JSON.stringify(session.turns), now);
|
|
120
|
-
|
|
184
|
+
upsertStmt.run(session.sessionId, session.tool, session.model, session.startedAt, session.endedAt, session.inputTokens, session.outputTokens, session.cacheReadTokens, session.cacheWriteTokens, session.costUsd, session.costType, session.subscriptionPlan ?? null, session.unmatchedTurns, session.repoName, session.gitBranch, session.workingDir, session.turnCount, session.filesTouchedCount, JSON.stringify(session.turns), now);
|
|
185
|
+
if (!existing) {
|
|
186
|
+
syncInsertStmt.run(session.sessionId);
|
|
187
|
+
}
|
|
188
|
+
else if (session.turnCount > existing.turnCount) {
|
|
189
|
+
// Session got new turns — re-queue for sync so the backend sees the update.
|
|
190
|
+
syncResetStmt.run(session.sessionId);
|
|
191
|
+
}
|
|
121
192
|
}
|
|
122
193
|
});
|
|
123
194
|
run();
|
|
@@ -128,13 +199,20 @@ export function getSessions() {
|
|
|
128
199
|
.prepare("SELECT * FROM sessions ORDER BY startedAt DESC")
|
|
129
200
|
.all();
|
|
130
201
|
}
|
|
202
|
+
/**
|
|
203
|
+
* Sessions that have not yet been synced, including turnsJson and merge metadata.
|
|
204
|
+
* turnsJson is included so buildTelemetryPayload can extract per-turn metadata;
|
|
205
|
+
* the privacy invariant is enforced there (explicit field mapping, never forwarded raw).
|
|
206
|
+
*/
|
|
131
207
|
export function getUnsyncedSessions() {
|
|
132
208
|
return getDb()
|
|
133
209
|
.prepare(`
|
|
134
210
|
SELECT s.id, s.tool, s.model, s.startedAt, s.endedAt,
|
|
135
211
|
s.inputTokens, s.outputTokens, s.cacheReadTokens, s.cacheWriteTokens,
|
|
136
|
-
s.costUsd, s.
|
|
137
|
-
s.
|
|
212
|
+
s.costUsd, s.costType, s.subscriptionPlan, s.unmatchedTurns,
|
|
213
|
+
s.repoName, s.gitBranch, s.gitAuthorEmail, s.workingDir,
|
|
214
|
+
s.turnCount, s.filesTouchedCount, s.outcome, s.turnsJson, s.scrapedAt,
|
|
215
|
+
s.mergedPrNumber, s.mergedAt, s.timeToMergeMs
|
|
138
216
|
FROM sessions s
|
|
139
217
|
LEFT JOIN sync_state ss ON s.id = ss.sessionId
|
|
140
218
|
WHERE ss.syncedAt IS NULL
|
|
@@ -142,11 +220,27 @@ export function getUnsyncedSessions() {
|
|
|
142
220
|
`)
|
|
143
221
|
.all();
|
|
144
222
|
}
|
|
223
|
+
/** Full session row by ID — used by `planck inspect`. Returns null if not found. */
|
|
224
|
+
export function getSessionById(id) {
|
|
225
|
+
return (getDb()
|
|
226
|
+
.prepare("SELECT * FROM sessions WHERE id = ?")
|
|
227
|
+
.get(id) ?? null);
|
|
228
|
+
}
|
|
229
|
+
export function getSessionsForValue(tool, sinceIso) {
|
|
230
|
+
return getDb()
|
|
231
|
+
.prepare(`
|
|
232
|
+
SELECT tool, costUsd, costType, gitAuthorEmail
|
|
233
|
+
FROM sessions
|
|
234
|
+
WHERE tool = ? AND startedAt >= ?
|
|
235
|
+
ORDER BY startedAt DESC
|
|
236
|
+
`)
|
|
237
|
+
.all(tool, sinceIso);
|
|
238
|
+
}
|
|
145
239
|
/** Sessions to feed the git correlator — only the fields it needs to classify outcomes. */
|
|
146
240
|
export function getSessionsForCorrelation() {
|
|
147
241
|
return getDb()
|
|
148
242
|
.prepare(`
|
|
149
|
-
SELECT id, repoName, gitBranch, workingDir, startedAt, endedAt, outcome
|
|
243
|
+
SELECT id, repoName, gitBranch, workingDir, startedAt, endedAt, outcome, gitAuthorEmail
|
|
150
244
|
FROM sessions
|
|
151
245
|
`)
|
|
152
246
|
.all();
|
|
@@ -157,6 +251,37 @@ export function setSessionCorrelation(id, outcome, gitAuthorEmail) {
|
|
|
157
251
|
.prepare("UPDATE sessions SET outcome = ?, gitAuthorEmail = ? WHERE id = ?")
|
|
158
252
|
.run(outcome, gitAuthorEmail, id);
|
|
159
253
|
}
|
|
254
|
+
/**
|
|
255
|
+
* Persist merge metadata for a shipped session.
|
|
256
|
+
* Called after correlation determines outcome = "shipped".
|
|
257
|
+
* Clears these fields for non-shipped sessions when called with nulls.
|
|
258
|
+
*/
|
|
259
|
+
export function setSessionMergeInfo(id, mergedPrNumber, mergedAt, timeToMergeMs) {
|
|
260
|
+
getDb()
|
|
261
|
+
.prepare("UPDATE sessions SET mergedPrNumber = ?, mergedAt = ?, timeToMergeMs = ? WHERE id = ?")
|
|
262
|
+
.run(mergedPrNumber, mergedAt, timeToMergeMs, id);
|
|
263
|
+
}
|
|
264
|
+
export function getSessionsForMetrics(sinceIso) {
|
|
265
|
+
if (sinceIso) {
|
|
266
|
+
return getDb()
|
|
267
|
+
.prepare(`
|
|
268
|
+
SELECT id, costUsd, outcome, gitBranch, repoName, workingDir, startedAt,
|
|
269
|
+
gitAuthorEmail, mergedPrNumber, mergedAt, timeToMergeMs
|
|
270
|
+
FROM sessions
|
|
271
|
+
WHERE startedAt >= ?
|
|
272
|
+
ORDER BY startedAt DESC
|
|
273
|
+
`)
|
|
274
|
+
.all(sinceIso);
|
|
275
|
+
}
|
|
276
|
+
return getDb()
|
|
277
|
+
.prepare(`
|
|
278
|
+
SELECT id, costUsd, outcome, gitBranch, repoName, workingDir, startedAt,
|
|
279
|
+
gitAuthorEmail, mergedPrNumber, mergedAt, timeToMergeMs
|
|
280
|
+
FROM sessions
|
|
281
|
+
ORDER BY startedAt DESC
|
|
282
|
+
`)
|
|
283
|
+
.all();
|
|
284
|
+
}
|
|
160
285
|
/** Mark sessions as successfully synced (sets syncedAt, clears lastError). */
|
|
161
286
|
export function markSessionsSynced(ids) {
|
|
162
287
|
if (ids.length === 0)
|
|
@@ -176,6 +301,16 @@ export function markSessionsSynced(ids) {
|
|
|
176
301
|
});
|
|
177
302
|
run();
|
|
178
303
|
}
|
|
304
|
+
/**
|
|
305
|
+
* Reset sync state for all sessions, forcing a full re-sync on next run.
|
|
306
|
+
* Called when switching to a different workspace so previous sessions are
|
|
307
|
+
* sent to the new workspace rather than silently skipped as already-synced.
|
|
308
|
+
*/
|
|
309
|
+
export function resetSyncState() {
|
|
310
|
+
getDb()
|
|
311
|
+
.prepare("UPDATE sync_state SET syncedAt = NULL, lastError = NULL")
|
|
312
|
+
.run();
|
|
313
|
+
}
|
|
179
314
|
/** Record a sync failure; leaves syncedAt NULL so the rows retry next run. */
|
|
180
315
|
export function recordSyncError(ids, error) {
|
|
181
316
|
if (ids.length === 0)
|
|
@@ -207,4 +342,255 @@ export function getMeta(key) {
|
|
|
207
342
|
.get(key);
|
|
208
343
|
return row?.value ?? null;
|
|
209
344
|
}
|
|
345
|
+
// ── connection state ──────────────────────────────────────────────────────────
|
|
346
|
+
export function getConnectionState(key) {
|
|
347
|
+
const row = getDb()
|
|
348
|
+
.prepare("SELECT value FROM connection_state WHERE key = ?")
|
|
349
|
+
.get(key);
|
|
350
|
+
return row?.value ?? null;
|
|
351
|
+
}
|
|
352
|
+
export function setConnectionState(key, value) {
|
|
353
|
+
getDb()
|
|
354
|
+
.prepare(`
|
|
355
|
+
INSERT INTO connection_state (key, value) VALUES (?, ?)
|
|
356
|
+
ON CONFLICT(key) DO UPDATE SET value = excluded.value
|
|
357
|
+
`)
|
|
358
|
+
.run(key, value);
|
|
359
|
+
}
|
|
360
|
+
/** Session IDs that have been successfully synced (syncedAt IS NOT NULL). */
|
|
361
|
+
export function getSyncedSessionIds() {
|
|
362
|
+
return getDb()
|
|
363
|
+
.prepare("SELECT sessionId FROM sync_state WHERE syncedAt IS NOT NULL")
|
|
364
|
+
.all().map((r) => r.sessionId);
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Reset sync state for specific sessions so they are re-sent on the next sync.
|
|
368
|
+
* Used by reconcileWithManifest when sessions are missing from the backend.
|
|
369
|
+
*/
|
|
370
|
+
export function resetSyncStateForIds(ids, reason) {
|
|
371
|
+
if (ids.length === 0)
|
|
372
|
+
return;
|
|
373
|
+
const db = getDb();
|
|
374
|
+
const stmt = db.prepare("UPDATE sync_state SET syncedAt = NULL, lastError = ? WHERE sessionId = ?");
|
|
375
|
+
const run = db.transaction(() => {
|
|
376
|
+
for (const id of ids)
|
|
377
|
+
stmt.run(reason, id);
|
|
378
|
+
});
|
|
379
|
+
run();
|
|
380
|
+
}
|
|
381
|
+
/** Total number of sessions in the local DB (cheap COUNT, no row loading). */
|
|
382
|
+
export function getSessionCount() {
|
|
383
|
+
const row = getDb()
|
|
384
|
+
.prepare("SELECT COUNT(*) as count FROM sessions")
|
|
385
|
+
.get();
|
|
386
|
+
return row?.count ?? 0;
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* Stable ID for an insight: detectorId + repo + short title slug.
|
|
390
|
+
* Stable across runs for the same finding so upserts overwrite rather than accumulate.
|
|
391
|
+
*/
|
|
392
|
+
function insightId(insight) {
|
|
393
|
+
const repo = (insight.repoName ?? "workspace")
|
|
394
|
+
.replace(/[^a-zA-Z0-9_-]/g, "_")
|
|
395
|
+
.slice(0, 40);
|
|
396
|
+
const slug = insight.titleShort
|
|
397
|
+
.split(" ")
|
|
398
|
+
.slice(0, 5)
|
|
399
|
+
.join("-")
|
|
400
|
+
.replace(/[^a-zA-Z0-9-]/g, "")
|
|
401
|
+
.toLowerCase()
|
|
402
|
+
.slice(0, 30);
|
|
403
|
+
return `${insight.detectorId}:${repo}:${slug}`;
|
|
404
|
+
}
|
|
405
|
+
/** Upsert a batch of insights; resets syncedAt so updated findings re-sync. */
|
|
406
|
+
export function upsertInsights(insights) {
|
|
407
|
+
if (insights.length === 0)
|
|
408
|
+
return;
|
|
409
|
+
const db = getDb();
|
|
410
|
+
const now = new Date().toISOString();
|
|
411
|
+
const stmt = db.prepare(`
|
|
412
|
+
INSERT INTO insights (
|
|
413
|
+
id, detectorId, repoName, workspaceScope, titleShort,
|
|
414
|
+
estimatedMonthlySavingsUsd, confidence, evidenceJson, manualFix, createdAt, syncedAt
|
|
415
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NULL)
|
|
416
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
417
|
+
titleShort = excluded.titleShort,
|
|
418
|
+
estimatedMonthlySavingsUsd = excluded.estimatedMonthlySavingsUsd,
|
|
419
|
+
confidence = excluded.confidence,
|
|
420
|
+
evidenceJson = excluded.evidenceJson,
|
|
421
|
+
manualFix = excluded.manualFix,
|
|
422
|
+
createdAt = excluded.createdAt,
|
|
423
|
+
syncedAt = NULL
|
|
424
|
+
`);
|
|
425
|
+
const run = db.transaction(() => {
|
|
426
|
+
for (const insight of insights) {
|
|
427
|
+
stmt.run(insightId(insight), insight.detectorId, insight.repoName, insight.workspaceScope, insight.titleShort, insight.estimatedMonthlySavingsUsd, insight.confidence, JSON.stringify(insight.evidence), insight.manualFix, now);
|
|
428
|
+
}
|
|
429
|
+
});
|
|
430
|
+
run();
|
|
431
|
+
}
|
|
432
|
+
export function getUnsyncedInsights() {
|
|
433
|
+
return getDb()
|
|
434
|
+
.prepare("SELECT * FROM insights WHERE syncedAt IS NULL ORDER BY createdAt DESC")
|
|
435
|
+
.all();
|
|
436
|
+
}
|
|
437
|
+
export function markInsightsSynced(ids) {
|
|
438
|
+
if (ids.length === 0)
|
|
439
|
+
return;
|
|
440
|
+
const db = getDb();
|
|
441
|
+
const now = new Date().toISOString();
|
|
442
|
+
const stmt = db.prepare("UPDATE insights SET syncedAt = ? WHERE id = ?");
|
|
443
|
+
const run = db.transaction(() => {
|
|
444
|
+
for (const id of ids)
|
|
445
|
+
stmt.run(now, id);
|
|
446
|
+
});
|
|
447
|
+
run();
|
|
448
|
+
}
|
|
449
|
+
// ── file offsets (daemon incremental scraping) ────────────────────────────────
|
|
450
|
+
/** Returns the last processed byte offset for a file path, or 0 if unseen. */
|
|
451
|
+
export function getFileOffset(filePath) {
|
|
452
|
+
const row = getDb()
|
|
453
|
+
.prepare("SELECT byteOffset FROM file_offsets WHERE filePath = ?")
|
|
454
|
+
.get(filePath);
|
|
455
|
+
return row?.byteOffset ?? 0;
|
|
456
|
+
}
|
|
457
|
+
/** Record that a file has been fully processed up to the given byte offset. */
|
|
458
|
+
export function setFileOffset(filePath, byteOffset) {
|
|
459
|
+
getDb()
|
|
460
|
+
.prepare(`
|
|
461
|
+
INSERT INTO file_offsets (filePath, byteOffset, updatedAt)
|
|
462
|
+
VALUES (?, ?, ?)
|
|
463
|
+
ON CONFLICT(filePath) DO UPDATE SET
|
|
464
|
+
byteOffset = excluded.byteOffset,
|
|
465
|
+
updatedAt = excluded.updatedAt
|
|
466
|
+
`)
|
|
467
|
+
.run(filePath, byteOffset, new Date().toISOString());
|
|
468
|
+
}
|
|
469
|
+
/** Return all file paths whose stored offset is less than the given current size map. */
|
|
470
|
+
export function getFilesNeedingScrape(currentSizes) {
|
|
471
|
+
const db = getDb();
|
|
472
|
+
const rows = db
|
|
473
|
+
.prepare("SELECT filePath, byteOffset FROM file_offsets")
|
|
474
|
+
.all();
|
|
475
|
+
const knownOffsets = new Map(rows.map((r) => [r.filePath, r.byteOffset]));
|
|
476
|
+
const needsScrape = [];
|
|
477
|
+
for (const [fp, size] of currentSizes) {
|
|
478
|
+
const offset = knownOffsets.get(fp) ?? 0;
|
|
479
|
+
if (size > offset)
|
|
480
|
+
needsScrape.push(fp);
|
|
481
|
+
}
|
|
482
|
+
return needsScrape;
|
|
483
|
+
}
|
|
484
|
+
/**
|
|
485
|
+
* Insert anomaly events that don't already exist (deduplication by stable id).
|
|
486
|
+
* Returns only the newly inserted events so callers can report them to the user.
|
|
487
|
+
*/
|
|
488
|
+
export function upsertAnomalies(events) {
|
|
489
|
+
if (events.length === 0)
|
|
490
|
+
return [];
|
|
491
|
+
const db = getDb();
|
|
492
|
+
// Find which IDs already exist to return only the truly new ones.
|
|
493
|
+
const ids = events.map((e) => e.id);
|
|
494
|
+
const placeholders = ids.map(() => "?").join(",");
|
|
495
|
+
const existingIds = new Set(db
|
|
496
|
+
.prepare(`SELECT id FROM anomalies WHERE id IN (${placeholders})`)
|
|
497
|
+
.all(...ids).map((r) => r.id));
|
|
498
|
+
const newEvents = events.filter((e) => !existingIds.has(e.id));
|
|
499
|
+
if (newEvents.length === 0)
|
|
500
|
+
return [];
|
|
501
|
+
const stmt = db.prepare(`
|
|
502
|
+
INSERT OR IGNORE INTO anomalies
|
|
503
|
+
(id, type, repoName, sessionId, costUsd, baselineUsd, ratio, detectedAt, syncedAt)
|
|
504
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, NULL)
|
|
505
|
+
`);
|
|
506
|
+
const run = db.transaction(() => {
|
|
507
|
+
for (const e of newEvents) {
|
|
508
|
+
stmt.run(e.id, e.type, e.repoName, e.sessionId, e.costUsd, e.baselineUsd, e.ratio, e.detectedAt);
|
|
509
|
+
}
|
|
510
|
+
});
|
|
511
|
+
run();
|
|
512
|
+
return newEvents;
|
|
513
|
+
}
|
|
514
|
+
export function getUnsyncedAnomalies() {
|
|
515
|
+
return getDb()
|
|
516
|
+
.prepare("SELECT * FROM anomalies WHERE syncedAt IS NULL ORDER BY detectedAt DESC")
|
|
517
|
+
.all();
|
|
518
|
+
}
|
|
519
|
+
export function markAnomaliesSynced(ids) {
|
|
520
|
+
if (ids.length === 0)
|
|
521
|
+
return;
|
|
522
|
+
const db = getDb();
|
|
523
|
+
const now = new Date().toISOString();
|
|
524
|
+
const stmt = db.prepare("UPDATE anomalies SET syncedAt = ? WHERE id = ?");
|
|
525
|
+
const run = db.transaction(() => {
|
|
526
|
+
for (const id of ids)
|
|
527
|
+
stmt.run(now, id);
|
|
528
|
+
});
|
|
529
|
+
run();
|
|
530
|
+
}
|
|
531
|
+
// ── anomaly detector queries ──────────────────────────────────────────────────
|
|
532
|
+
/** Daily cost totals per repo for the given time window; ordered by repoName, day ASC. */
|
|
533
|
+
export function getDailySessionCosts(since) {
|
|
534
|
+
return getDb()
|
|
535
|
+
.prepare(`
|
|
536
|
+
SELECT repoName, date(startedAt) as day, SUM(costUsd) as dailyCost
|
|
537
|
+
FROM sessions
|
|
538
|
+
WHERE startedAt >= ?
|
|
539
|
+
GROUP BY repoName, date(startedAt)
|
|
540
|
+
ORDER BY repoName, day ASC
|
|
541
|
+
`)
|
|
542
|
+
.all(since);
|
|
543
|
+
}
|
|
544
|
+
/** Sessions with a known developer email; ordered by gitAuthorEmail, costUsd ASC. */
|
|
545
|
+
export function getSessionsForAnomalyDetection(since) {
|
|
546
|
+
return getDb()
|
|
547
|
+
.prepare(`
|
|
548
|
+
SELECT id, gitAuthorEmail, costUsd, repoName
|
|
549
|
+
FROM sessions
|
|
550
|
+
WHERE startedAt >= ?
|
|
551
|
+
AND costUsd > 0
|
|
552
|
+
AND gitAuthorEmail IS NOT NULL
|
|
553
|
+
ORDER BY gitAuthorEmail, costUsd ASC
|
|
554
|
+
`)
|
|
555
|
+
.all(since);
|
|
556
|
+
}
|
|
557
|
+
export function getSessionsForExport(monthStart, monthEnd) {
|
|
558
|
+
return getDb()
|
|
559
|
+
.prepare(`
|
|
560
|
+
SELECT id, tool, model, startedAt, endedAt,
|
|
561
|
+
inputTokens, outputTokens, cacheReadTokens, cacheWriteTokens,
|
|
562
|
+
costUsd, costType, subscriptionPlan, unmatchedTurns,
|
|
563
|
+
repoName, gitBranch, gitAuthorEmail, workingDir,
|
|
564
|
+
turnCount, filesTouchedCount, outcome, scrapedAt,
|
|
565
|
+
mergedPrNumber, mergedAt, timeToMergeMs
|
|
566
|
+
FROM sessions
|
|
567
|
+
WHERE startedAt >= ? AND startedAt < ?
|
|
568
|
+
ORDER BY startedAt ASC
|
|
569
|
+
`)
|
|
570
|
+
.all(monthStart, monthEnd);
|
|
571
|
+
}
|
|
572
|
+
// ── budget queries ────────────────────────────────────────────────────────────
|
|
573
|
+
/**
|
|
574
|
+
* Total session cost since `monthStart`, broken down by repoName.
|
|
575
|
+
* Used to compute burn-rate for configured budgets.
|
|
576
|
+
*/
|
|
577
|
+
export function getMonthlyCosts(monthStart) {
|
|
578
|
+
const rows = getDb()
|
|
579
|
+
.prepare(`
|
|
580
|
+
SELECT repoName, SUM(costUsd) as totalCost
|
|
581
|
+
FROM sessions
|
|
582
|
+
WHERE startedAt >= ?
|
|
583
|
+
GROUP BY repoName
|
|
584
|
+
`)
|
|
585
|
+
.all(monthStart);
|
|
586
|
+
const byRepo = new Map();
|
|
587
|
+
let total = 0;
|
|
588
|
+
for (const r of rows) {
|
|
589
|
+
total += r.totalCost;
|
|
590
|
+
if (r.repoName) {
|
|
591
|
+
byRepo.set(r.repoName, (byRepo.get(r.repoName) ?? 0) + r.totalCost);
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
return { byRepo, total };
|
|
595
|
+
}
|
|
210
596
|
//# sourceMappingURL=store.js.map
|
package/dist/db/store.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/db/store.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/db/store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache-gap.d.ts","sourceRoot":"","sources":["../../src/detectors/cache-gap.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAoB,MAAM,YAAY,CAAC;AAU7D,eAAO,MAAM,gBAAgB,EAAE,QA6E9B,CAAC"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
const DAYS_30_MS = 30 * 24 * 60 * 60 * 1000;
|
|
2
|
+
const CACHE_RATIO_THRESHOLD = 0.30; // < 30% cache-hit ratio triggers
|
|
3
|
+
const TOKEN_VOLUME_THRESHOLD = 1_000_000; // > 1M tokens/month in that repo
|
|
4
|
+
const INPUT_RATE_PER_M = 3.00; // Sonnet 4 baseline, $/M input tokens
|
|
5
|
+
const CACHEABLE_FRACTION = 0.50; // conservative: ~50% of input could be cached
|
|
6
|
+
const CACHE_READ_FRACTION = 0.10; // cache reads cost 0.1× the input rate
|
|
7
|
+
const MIN_SESSIONS = 5;
|
|
8
|
+
export const cacheGapDetector = {
|
|
9
|
+
id: "cache-gap",
|
|
10
|
+
description: "Repo has high token volume but low cache-hit ratio — prompt caching not configured",
|
|
11
|
+
minSessionsRequired: MIN_SESSIONS,
|
|
12
|
+
detect(sessions) {
|
|
13
|
+
if (sessions.length < MIN_SESSIONS)
|
|
14
|
+
return [];
|
|
15
|
+
const since = new Date(Date.now() - DAYS_30_MS).toISOString();
|
|
16
|
+
const recent = sessions.filter((s) => s.startedAt >= since);
|
|
17
|
+
const repoMap = new Map();
|
|
18
|
+
for (const session of recent) {
|
|
19
|
+
const key = session.repoName ?? "_unattributed";
|
|
20
|
+
if (!repoMap.has(key)) {
|
|
21
|
+
repoMap.set(key, { sessions: [], inputTokens: 0, cacheReadTokens: 0 });
|
|
22
|
+
}
|
|
23
|
+
const entry = repoMap.get(key);
|
|
24
|
+
entry.sessions.push(session);
|
|
25
|
+
entry.inputTokens += session.inputTokens;
|
|
26
|
+
entry.cacheReadTokens += session.cacheReadTokens;
|
|
27
|
+
}
|
|
28
|
+
const insights = [];
|
|
29
|
+
for (const [repoKey, { sessions: repoSessions, inputTokens, cacheReadTokens }] of repoMap) {
|
|
30
|
+
const totalVolume = inputTokens + cacheReadTokens;
|
|
31
|
+
if (totalVolume < TOKEN_VOLUME_THRESHOLD)
|
|
32
|
+
continue;
|
|
33
|
+
const cacheRatio = totalVolume > 0 ? cacheReadTokens / totalVolume : 0;
|
|
34
|
+
if (cacheRatio >= CACHE_RATIO_THRESHOLD)
|
|
35
|
+
continue;
|
|
36
|
+
// Savings = cacheable tokens × (input rate - cache read rate)
|
|
37
|
+
const monthlySavingsUsd = (inputTokens * CACHEABLE_FRACTION * (1 - CACHE_READ_FRACTION) * INPUT_RATE_PER_M) /
|
|
38
|
+
1_000_000;
|
|
39
|
+
const repoName = repoKey === "_unattributed" ? null : repoKey;
|
|
40
|
+
const cacheRatioPct = (cacheRatio * 100).toFixed(1);
|
|
41
|
+
const volumeMStr = (totalVolume / 1_000_000).toFixed(1);
|
|
42
|
+
insights.push({
|
|
43
|
+
detectorId: "cache-gap",
|
|
44
|
+
repoName,
|
|
45
|
+
workspaceScope: "repo",
|
|
46
|
+
titleShort: `${repoKey}: ${cacheRatioPct}% cache-hit ratio on ${volumeMStr}M tokens/month`,
|
|
47
|
+
estimatedMonthlySavingsUsd: monthlySavingsUsd,
|
|
48
|
+
confidence: "medium",
|
|
49
|
+
evidence: {
|
|
50
|
+
sessionIds: repoSessions.map((s) => s.id),
|
|
51
|
+
metrics: {
|
|
52
|
+
inputTokens,
|
|
53
|
+
cacheReadTokens,
|
|
54
|
+
cacheRatioPct: parseFloat(cacheRatioPct),
|
|
55
|
+
totalVolumeM: parseFloat(volumeMStr),
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
manualFix: `Prompt caching is not used effectively in \`${repoKey}\`. Cache-hit ratio is` +
|
|
59
|
+
` ${cacheRatioPct}%, well below the 30% threshold, on ${volumeMStr}M tokens/month.\n\n` +
|
|
60
|
+
`To enable caching: ensure the stable prefix of each prompt (CLAUDE.md, project context,` +
|
|
61
|
+
` system instructions) comes before the dynamic user turn and exceeds ~2048 tokens.` +
|
|
62
|
+
` Claude Code caches this prefix automatically with a 5-minute TTL. If sessions are very` +
|
|
63
|
+
` short, group related tasks into longer sessions so the cache-write cost amortises across` +
|
|
64
|
+
` more turns.`,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
return insights;
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
//# sourceMappingURL=cache-gap.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache-gap.js","sourceRoot":"","sources":["../../src/detectors/cache-gap.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-bloat.d.ts","sourceRoot":"","sources":["../../src/detectors/context-bloat.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAoB,MAAM,YAAY,CAAC;AAc7D,eAAO,MAAM,oBAAoB,EAAE,QAiElC,CAAC"}
|