@ai-studio-3d/vyasa 0.1.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 +69 -0
- package/data/common-kit.json +34 -0
- package/data/pricing.json +119 -0
- package/data/schema/AnalyticsData.json +214 -0
- package/data/schema/FoundationData.json +42 -0
- package/data/schema/KitData.json +321 -0
- package/data/schema/SearchData.json +173 -0
- package/data/schema/SessionDetailData.json +231 -0
- package/data/schema/SessionsListData.json +115 -0
- package/data/schema/WasteData.json +95 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +343 -0
- package/dist/cli.js.map +1 -0
- package/dist/core/billing/index.d.ts +4 -0
- package/dist/core/billing/index.d.ts.map +1 -0
- package/dist/core/billing/index.js +43 -0
- package/dist/core/billing/index.js.map +1 -0
- package/dist/core/budget/index.d.ts +30 -0
- package/dist/core/budget/index.d.ts.map +1 -0
- package/dist/core/budget/index.js +61 -0
- package/dist/core/budget/index.js.map +1 -0
- package/dist/core/codex/index.d.ts +3 -0
- package/dist/core/codex/index.d.ts.map +1 -0
- package/dist/core/codex/index.js +212 -0
- package/dist/core/codex/index.js.map +1 -0
- package/dist/core/cursor/index.d.ts +3 -0
- package/dist/core/cursor/index.d.ts.map +1 -0
- package/dist/core/cursor/index.js +304 -0
- package/dist/core/cursor/index.js.map +1 -0
- package/dist/core/cursor/scan.d.ts +28 -0
- package/dist/core/cursor/scan.d.ts.map +1 -0
- package/dist/core/cursor/scan.js +79 -0
- package/dist/core/cursor/scan.js.map +1 -0
- package/dist/core/decisions/index.d.ts +21 -0
- package/dist/core/decisions/index.d.ts.map +1 -0
- package/dist/core/decisions/index.js +133 -0
- package/dist/core/decisions/index.js.map +1 -0
- package/dist/core/dlp/index.d.ts +7 -0
- package/dist/core/dlp/index.d.ts.map +1 -0
- package/dist/core/dlp/index.js +115 -0
- package/dist/core/dlp/index.js.map +1 -0
- package/dist/core/health/index.d.ts +10 -0
- package/dist/core/health/index.d.ts.map +1 -0
- package/dist/core/health/index.js +21 -0
- package/dist/core/health/index.js.map +1 -0
- package/dist/core/index/index.d.ts +9 -0
- package/dist/core/index/index.d.ts.map +1 -0
- package/dist/core/index/index.js +103 -0
- package/dist/core/index/index.js.map +1 -0
- package/dist/core/index/ingest.d.ts +16 -0
- package/dist/core/index/ingest.d.ts.map +1 -0
- package/dist/core/index/ingest.js +184 -0
- package/dist/core/index/ingest.js.map +1 -0
- package/dist/core/index/platforms.d.ts +21 -0
- package/dist/core/index/platforms.d.ts.map +1 -0
- package/dist/core/index/platforms.js +44 -0
- package/dist/core/index/platforms.js.map +1 -0
- package/dist/core/index/pricing-map.d.ts +10 -0
- package/dist/core/index/pricing-map.d.ts.map +1 -0
- package/dist/core/index/pricing-map.js +16 -0
- package/dist/core/index/pricing-map.js.map +1 -0
- package/dist/core/index/progress.d.ts +26 -0
- package/dist/core/index/progress.d.ts.map +1 -0
- package/dist/core/index/progress.js +59 -0
- package/dist/core/index/progress.js.map +1 -0
- package/dist/core/index/scan.d.ts +9 -0
- package/dist/core/index/scan.d.ts.map +1 -0
- package/dist/core/index/scan.js +42 -0
- package/dist/core/index/scan.js.map +1 -0
- package/dist/core/index/statements.d.ts +18 -0
- package/dist/core/index/statements.d.ts.map +1 -0
- package/dist/core/index/statements.js +82 -0
- package/dist/core/index/statements.js.map +1 -0
- package/dist/core/index/tail.d.ts +42 -0
- package/dist/core/index/tail.d.ts.map +1 -0
- package/dist/core/index/tail.js +123 -0
- package/dist/core/index/tail.js.map +1 -0
- package/dist/core/jsonl/index.d.ts +3 -0
- package/dist/core/jsonl/index.d.ts.map +1 -0
- package/dist/core/jsonl/index.js +106 -0
- package/dist/core/jsonl/index.js.map +1 -0
- package/dist/core/jsonl-validate/index.d.ts +10 -0
- package/dist/core/jsonl-validate/index.d.ts.map +1 -0
- package/dist/core/jsonl-validate/index.js +40 -0
- package/dist/core/jsonl-validate/index.js.map +1 -0
- package/dist/core/kit/detection.d.ts +94 -0
- package/dist/core/kit/detection.d.ts.map +1 -0
- package/dist/core/kit/detection.js +312 -0
- package/dist/core/kit/detection.js.map +1 -0
- package/dist/core/kit/index.d.ts +12 -0
- package/dist/core/kit/index.d.ts.map +1 -0
- package/dist/core/kit/index.js +131 -0
- package/dist/core/kit/index.js.map +1 -0
- package/dist/core/kit/scan.d.ts +28 -0
- package/dist/core/kit/scan.d.ts.map +1 -0
- package/dist/core/kit/scan.js +432 -0
- package/dist/core/kit/scan.js.map +1 -0
- package/dist/core/recap/index.d.ts +18 -0
- package/dist/core/recap/index.d.ts.map +1 -0
- package/dist/core/recap/index.js +88 -0
- package/dist/core/recap/index.js.map +1 -0
- package/dist/core/repetition/index.d.ts +5 -0
- package/dist/core/repetition/index.d.ts.map +1 -0
- package/dist/core/repetition/index.js +0 -0
- package/dist/core/repetition/index.js.map +1 -0
- package/dist/core/schema/index.d.ts +514 -0
- package/dist/core/schema/index.d.ts.map +1 -0
- package/dist/core/schema/index.js +2 -0
- package/dist/core/schema/index.js.map +1 -0
- package/dist/core/schema-watch/index.d.ts +34 -0
- package/dist/core/schema-watch/index.d.ts.map +1 -0
- package/dist/core/schema-watch/index.js +87 -0
- package/dist/core/schema-watch/index.js.map +1 -0
- package/dist/core/search/index.d.ts +44 -0
- package/dist/core/search/index.d.ts.map +1 -0
- package/dist/core/search/index.js +641 -0
- package/dist/core/search/index.js.map +1 -0
- package/dist/core/settings/index.d.ts +24 -0
- package/dist/core/settings/index.d.ts.map +1 -0
- package/dist/core/settings/index.js +76 -0
- package/dist/core/settings/index.js.map +1 -0
- package/dist/core/share/bundle.d.ts +40 -0
- package/dist/core/share/bundle.d.ts.map +1 -0
- package/dist/core/share/bundle.js +158 -0
- package/dist/core/share/bundle.js.map +1 -0
- package/dist/core/share/canonical/from-claude.d.ts +13 -0
- package/dist/core/share/canonical/from-claude.d.ts.map +1 -0
- package/dist/core/share/canonical/from-claude.js +129 -0
- package/dist/core/share/canonical/from-claude.js.map +1 -0
- package/dist/core/share/canonical/from-codex.d.ts +18 -0
- package/dist/core/share/canonical/from-codex.d.ts.map +1 -0
- package/dist/core/share/canonical/from-codex.js +183 -0
- package/dist/core/share/canonical/from-codex.js.map +1 -0
- package/dist/core/share/canonical/to-claude.d.ts +15 -0
- package/dist/core/share/canonical/to-claude.d.ts.map +1 -0
- package/dist/core/share/canonical/to-claude.js +146 -0
- package/dist/core/share/canonical/to-claude.js.map +1 -0
- package/dist/core/share/canonical/to-codex.d.ts +21 -0
- package/dist/core/share/canonical/to-codex.d.ts.map +1 -0
- package/dist/core/share/canonical/to-codex.js +124 -0
- package/dist/core/share/canonical/to-codex.js.map +1 -0
- package/dist/core/share/canonical/tool-map.d.ts +61 -0
- package/dist/core/share/canonical/tool-map.d.ts.map +1 -0
- package/dist/core/share/canonical/tool-map.js +299 -0
- package/dist/core/share/canonical/tool-map.js.map +1 -0
- package/dist/core/share/canonical/types.d.ts +57 -0
- package/dist/core/share/canonical/types.d.ts.map +1 -0
- package/dist/core/share/canonical/types.js +9 -0
- package/dist/core/share/canonical/types.js.map +1 -0
- package/dist/core/share/import.d.ts +28 -0
- package/dist/core/share/import.d.ts.map +1 -0
- package/dist/core/share/import.js +174 -0
- package/dist/core/share/import.js.map +1 -0
- package/dist/core/share/manifest.d.ts +37 -0
- package/dist/core/share/manifest.d.ts.map +1 -0
- package/dist/core/share/manifest.js +31 -0
- package/dist/core/share/manifest.js.map +1 -0
- package/dist/core/share/preview.d.ts +4 -0
- package/dist/core/share/preview.d.ts.map +1 -0
- package/dist/core/share/preview.js +153 -0
- package/dist/core/share/preview.js.map +1 -0
- package/dist/core/share/primer.d.ts +19 -0
- package/dist/core/share/primer.d.ts.map +1 -0
- package/dist/core/share/primer.js +196 -0
- package/dist/core/share/primer.js.map +1 -0
- package/dist/core/share/resume.d.ts +10 -0
- package/dist/core/share/resume.d.ts.map +1 -0
- package/dist/core/share/resume.js +58 -0
- package/dist/core/share/resume.js.map +1 -0
- package/dist/core/share/scrub.d.ts +10 -0
- package/dist/core/share/scrub.d.ts.map +1 -0
- package/dist/core/share/scrub.js +198 -0
- package/dist/core/share/scrub.js.map +1 -0
- package/dist/core/share/tar.d.ts +12 -0
- package/dist/core/share/tar.d.ts.map +1 -0
- package/dist/core/share/tar.js +78 -0
- package/dist/core/share/tar.js.map +1 -0
- package/dist/core/tags/index.d.ts +48 -0
- package/dist/core/tags/index.d.ts.map +1 -0
- package/dist/core/tags/index.js +113 -0
- package/dist/core/tags/index.js.map +1 -0
- package/dist/core/today/index.d.ts +25 -0
- package/dist/core/today/index.d.ts.map +1 -0
- package/dist/core/today/index.js +42 -0
- package/dist/core/today/index.js.map +1 -0
- package/dist/core/waste/abandoned.d.ts +12 -0
- package/dist/core/waste/abandoned.d.ts.map +1 -0
- package/dist/core/waste/abandoned.js +127 -0
- package/dist/core/waste/abandoned.js.map +1 -0
- package/dist/core/waste/cache-miss.d.ts +9 -0
- package/dist/core/waste/cache-miss.d.ts.map +1 -0
- package/dist/core/waste/cache-miss.js +84 -0
- package/dist/core/waste/cache-miss.js.map +1 -0
- package/dist/core/waste/index.d.ts +12 -0
- package/dist/core/waste/index.d.ts.map +1 -0
- package/dist/core/waste/index.js +45 -0
- package/dist/core/waste/index.js.map +1 -0
- package/dist/core/waste/wrong-model.d.ts +11 -0
- package/dist/core/waste/wrong-model.d.ts.map +1 -0
- package/dist/core/waste/wrong-model.js +104 -0
- package/dist/core/waste/wrong-model.js.map +1 -0
- package/dist/db/index.d.ts +10 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +29 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/migrate.d.ts +8 -0
- package/dist/db/migrate.d.ts.map +1 -0
- package/dist/db/migrate.js +282 -0
- package/dist/db/migrate.js.map +1 -0
- package/dist/server/events.d.ts +4 -0
- package/dist/server/events.d.ts.map +1 -0
- package/dist/server/events.js +54 -0
- package/dist/server/events.js.map +1 -0
- package/dist/server/index.d.ts +7 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +238 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/routes/foundation.d.ts +2 -0
- package/dist/server/routes/foundation.d.ts.map +1 -0
- package/dist/server/routes/foundation.js +2 -0
- package/dist/server/routes/foundation.js.map +1 -0
- package/dist/server/routes/search.d.ts +2 -0
- package/dist/server/routes/search.d.ts.map +1 -0
- package/dist/server/routes/search.js +2 -0
- package/dist/server/routes/search.js.map +1 -0
- package/dist/server/routes/sessions.d.ts +2 -0
- package/dist/server/routes/sessions.d.ts.map +1 -0
- package/dist/server/routes/sessions.js +2 -0
- package/dist/server/routes/sessions.js.map +1 -0
- package/dist/server/routes/waste.d.ts +2 -0
- package/dist/server/routes/waste.d.ts.map +1 -0
- package/dist/server/routes/waste.js +2 -0
- package/dist/server/routes/waste.js.map +1 -0
- package/dist/web/assets/index-Ba1VvTj0.js +37 -0
- package/dist/web/index.html +12 -0
- package/package.json +76 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Surgical confidentiality scrubber for Claude Code session JSONL, run on export.
|
|
3
|
+
*
|
|
4
|
+
* Primary effect (verified against real sessions): drops Claude Code's internal
|
|
5
|
+
* state records — `file-history-snapshot` (file backups), `last-prompt`,
|
|
6
|
+
* `ai-title`, etc. — which ship verbatim and are pure machine-state (and bloat).
|
|
7
|
+
* Defensively also strips sensitive-marker `<system-reminder>` spans IF any are
|
|
8
|
+
* persisted; note the CLAUDE.md/MEMORY.md/env injection is runtime-only and is
|
|
9
|
+
* NOT normally written to the transcript, so that path rarely fires in practice.
|
|
10
|
+
*
|
|
11
|
+
* Preserves the conversation, tool calls, the uuid/parentUuid chain (so `/resume`
|
|
12
|
+
* stays valid), attachments, and benign system-reminders (e.g. plan echoes).
|
|
13
|
+
* Operates at the raw-record level — NOT via the lossy canonical parsers.
|
|
14
|
+
*/
|
|
15
|
+
// Internal Claude Code state records, standalone (not part of the dialogue chain).
|
|
16
|
+
const INTERNAL_DROP_TYPES = new Set([
|
|
17
|
+
'ai-title',
|
|
18
|
+
'agent-name',
|
|
19
|
+
'last-prompt',
|
|
20
|
+
'permission-mode',
|
|
21
|
+
'file-history-snapshot',
|
|
22
|
+
'queue-operation',
|
|
23
|
+
]);
|
|
24
|
+
// A <system-reminder> span is sensitive (→ stripped) only if it carries one of
|
|
25
|
+
// these markers. Anything else (plan echoes, task reminders, tool guidance) is
|
|
26
|
+
// benign and kept, so plans and useful context survive replication.
|
|
27
|
+
const SENSITIVE_SR_MARKERS = [
|
|
28
|
+
'# claudeMd',
|
|
29
|
+
'Memory Index',
|
|
30
|
+
'# userEmail',
|
|
31
|
+
'# currentDate',
|
|
32
|
+
'This memory is', // recalled-memory staleness reminder
|
|
33
|
+
];
|
|
34
|
+
const SR_RE = /<system-reminder>[\s\S]*?<\/system-reminder>/g;
|
|
35
|
+
const REDACTED = '[redacted before sharing]';
|
|
36
|
+
export function scrubClaudeJsonl(raw, opts = {}) {
|
|
37
|
+
const redact = new Set(opts.redactUuids ?? []);
|
|
38
|
+
const report = {
|
|
39
|
+
metaRecordsDropped: {},
|
|
40
|
+
systemReminderSpansStripped: 0,
|
|
41
|
+
recordsEmptiedAndDropped: 0,
|
|
42
|
+
redactedRecords: 0,
|
|
43
|
+
bytesBefore: Buffer.byteLength(raw, 'utf8'),
|
|
44
|
+
bytesAfter: 0,
|
|
45
|
+
};
|
|
46
|
+
const dropParent = new Map(); // dropped uuid → its parentUuid
|
|
47
|
+
const kept = [];
|
|
48
|
+
for (const line of raw.split('\n')) {
|
|
49
|
+
const trimmed = line.trim();
|
|
50
|
+
if (!trimmed)
|
|
51
|
+
continue;
|
|
52
|
+
let rec;
|
|
53
|
+
try {
|
|
54
|
+
rec = JSON.parse(trimmed);
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
const type = typeof rec['type'] === 'string' ? rec['type'] : '';
|
|
60
|
+
const uuid = typeof rec['uuid'] === 'string' ? rec['uuid'] : '';
|
|
61
|
+
const parentUuid = (typeof rec['parentUuid'] === 'string' ? rec['parentUuid'] : null);
|
|
62
|
+
// 1. Drop internal-state record types.
|
|
63
|
+
if (INTERNAL_DROP_TYPES.has(type)) {
|
|
64
|
+
bump(report.metaRecordsDropped, type);
|
|
65
|
+
if (uuid)
|
|
66
|
+
dropParent.set(uuid, parentUuid);
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
// 2. Drop isMeta-flagged records (injected reminders).
|
|
70
|
+
if (rec['isMeta'] === true) {
|
|
71
|
+
bump(report.metaRecordsDropped, 'isMeta');
|
|
72
|
+
if (uuid)
|
|
73
|
+
dropParent.set(uuid, parentUuid);
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
// 3. Conversation records: strip sensitive SR spans (or redact in place).
|
|
77
|
+
if (type === 'user' || type === 'assistant' || type === 'system') {
|
|
78
|
+
const verdict = processConversationRecord(rec, type, uuid !== '' && redact.has(uuid), report);
|
|
79
|
+
if (verdict === 'drop') {
|
|
80
|
+
report.recordsEmptiedAndDropped += 1;
|
|
81
|
+
if (uuid)
|
|
82
|
+
dropParent.set(uuid, parentUuid);
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
kept.push(rec);
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
// attachment + anything else not internal → keep verbatim (may be real content).
|
|
89
|
+
kept.push(rec);
|
|
90
|
+
}
|
|
91
|
+
// 4. Chain repair: re-point each kept record's parentUuid through dropped
|
|
92
|
+
// ancestors to the nearest surviving record (or null).
|
|
93
|
+
for (const rec of kept) {
|
|
94
|
+
let p = (typeof rec['parentUuid'] === 'string' ? rec['parentUuid'] : null);
|
|
95
|
+
while (p != null && dropParent.has(p)) {
|
|
96
|
+
p = dropParent.get(p) ?? null;
|
|
97
|
+
}
|
|
98
|
+
if ('parentUuid' in rec)
|
|
99
|
+
rec['parentUuid'] = p;
|
|
100
|
+
}
|
|
101
|
+
const cleaned = kept.map((r) => JSON.stringify(r)).join('\n') + (kept.length ? '\n' : '');
|
|
102
|
+
report.bytesAfter = Buffer.byteLength(cleaned, 'utf8');
|
|
103
|
+
return { cleaned, report };
|
|
104
|
+
}
|
|
105
|
+
function bump(map, key) {
|
|
106
|
+
map[key] = (map[key] ?? 0) + 1;
|
|
107
|
+
}
|
|
108
|
+
/** Strip only sensitive-marker <system-reminder> spans; benign ones survive. */
|
|
109
|
+
function stripSensitiveSR(text) {
|
|
110
|
+
let stripped = 0;
|
|
111
|
+
const out = text.replace(SR_RE, (span) => {
|
|
112
|
+
if (SENSITIVE_SR_MARKERS.some((m) => span.includes(m))) {
|
|
113
|
+
stripped += 1;
|
|
114
|
+
return '';
|
|
115
|
+
}
|
|
116
|
+
return span;
|
|
117
|
+
});
|
|
118
|
+
return { text: out, stripped };
|
|
119
|
+
}
|
|
120
|
+
function redactContent(content) {
|
|
121
|
+
if (typeof content === 'string')
|
|
122
|
+
return REDACTED;
|
|
123
|
+
if (Array.isArray(content)) {
|
|
124
|
+
return content.map((block) => {
|
|
125
|
+
if (!block || typeof block !== 'object')
|
|
126
|
+
return block;
|
|
127
|
+
const b = { ...block };
|
|
128
|
+
if (b['type'] === 'text')
|
|
129
|
+
b['text'] = REDACTED;
|
|
130
|
+
else if (b['type'] === 'tool_result')
|
|
131
|
+
b['content'] = REDACTED;
|
|
132
|
+
else if (b['type'] === 'tool_use')
|
|
133
|
+
b['input'] = { redacted: true };
|
|
134
|
+
return b;
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
return content;
|
|
138
|
+
}
|
|
139
|
+
/** Returns 'drop' if the record has no meaningful content left, else 'keep' (mutates rec). */
|
|
140
|
+
function processConversationRecord(rec, type, redact, report) {
|
|
141
|
+
// System records carry content as a top-level string, not under message.
|
|
142
|
+
if (type === 'system') {
|
|
143
|
+
if (redact) {
|
|
144
|
+
rec['content'] = REDACTED;
|
|
145
|
+
report.redactedRecords += 1;
|
|
146
|
+
return 'keep';
|
|
147
|
+
}
|
|
148
|
+
if (typeof rec['content'] === 'string') {
|
|
149
|
+
const { text, stripped } = stripSensitiveSR(rec['content']);
|
|
150
|
+
report.systemReminderSpansStripped += stripped;
|
|
151
|
+
rec['content'] = text;
|
|
152
|
+
if (!text.trim())
|
|
153
|
+
return 'drop';
|
|
154
|
+
}
|
|
155
|
+
return 'keep';
|
|
156
|
+
}
|
|
157
|
+
const message = rec['message'];
|
|
158
|
+
if (!message)
|
|
159
|
+
return 'keep';
|
|
160
|
+
if (redact) {
|
|
161
|
+
message.content = redactContent(message.content);
|
|
162
|
+
report.redactedRecords += 1;
|
|
163
|
+
return 'keep';
|
|
164
|
+
}
|
|
165
|
+
const content = message.content;
|
|
166
|
+
if (typeof content === 'string') {
|
|
167
|
+
const { text, stripped } = stripSensitiveSR(content);
|
|
168
|
+
report.systemReminderSpansStripped += stripped;
|
|
169
|
+
message.content = text;
|
|
170
|
+
return text.trim() ? 'keep' : 'drop';
|
|
171
|
+
}
|
|
172
|
+
if (Array.isArray(content)) {
|
|
173
|
+
const out = [];
|
|
174
|
+
for (const block of content) {
|
|
175
|
+
if (!block || typeof block !== 'object') {
|
|
176
|
+
out.push(block);
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
const b = block;
|
|
180
|
+
if (b['type'] === 'text' && typeof b['text'] === 'string') {
|
|
181
|
+
const { text, stripped } = stripSensitiveSR(b['text']);
|
|
182
|
+
report.systemReminderSpansStripped += stripped;
|
|
183
|
+
if (text.trim()) {
|
|
184
|
+
b['text'] = text;
|
|
185
|
+
out.push(b);
|
|
186
|
+
}
|
|
187
|
+
// else: drop the now-empty (pure-injection) text block
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
out.push(block); // tool_use / tool_result / thinking / etc. kept
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
message.content = out;
|
|
194
|
+
return out.length > 0 ? 'keep' : 'drop';
|
|
195
|
+
}
|
|
196
|
+
return 'keep';
|
|
197
|
+
}
|
|
198
|
+
//# sourceMappingURL=scrub.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scrub.js","sourceRoot":"","sources":["../../../src/core/share/scrub.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface TarEntryIn {
|
|
2
|
+
name: string;
|
|
3
|
+
data: Buffer;
|
|
4
|
+
mtimeMs: number;
|
|
5
|
+
}
|
|
6
|
+
export interface TarEntryOut {
|
|
7
|
+
name: string;
|
|
8
|
+
data: Buffer;
|
|
9
|
+
}
|
|
10
|
+
export declare function tarPack(entries: TarEntryIn[]): Buffer;
|
|
11
|
+
export declare function tarUnpack(buf: Buffer): TarEntryOut[];
|
|
12
|
+
//# sourceMappingURL=tar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tar.d.ts","sourceRoot":"","sources":["../../../src/core/share/tar.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;CACb;AAmCD,wBAAgB,OAAO,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,MAAM,CAUrD;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,EAAE,CA6BpD"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
// Minimal POSIX (USTAR) tar writer + reader. Avoids a dependency for a small, well-defined format.
|
|
2
|
+
// Supports only what we need: regular files with names < 100 chars, sizes < 8 GB.
|
|
3
|
+
function octalField(n, len) {
|
|
4
|
+
// Right-aligned, zero-padded, null-terminated octal. Last byte is '\0'.
|
|
5
|
+
const s = n.toString(8).padStart(len - 1, '0');
|
|
6
|
+
const b = Buffer.alloc(len, 0);
|
|
7
|
+
b.write(s, 0, 'ascii');
|
|
8
|
+
return b;
|
|
9
|
+
}
|
|
10
|
+
function buildHeader(name, size, mtimeSec) {
|
|
11
|
+
if (Buffer.byteLength(name, 'utf8') > 100) {
|
|
12
|
+
throw new Error(`tar: filename too long (max 100 bytes): ${name}`);
|
|
13
|
+
}
|
|
14
|
+
const buf = Buffer.alloc(512, 0);
|
|
15
|
+
buf.write(name, 0, 100, 'utf8');
|
|
16
|
+
octalField(0o644, 8).copy(buf, 100); // mode
|
|
17
|
+
octalField(0, 8).copy(buf, 108); // uid
|
|
18
|
+
octalField(0, 8).copy(buf, 116); // gid
|
|
19
|
+
octalField(size, 12).copy(buf, 124); // size
|
|
20
|
+
octalField(mtimeSec, 12).copy(buf, 136); // mtime
|
|
21
|
+
buf.fill(0x20, 148, 156); // checksum: spaces during calculation
|
|
22
|
+
buf[156] = 0x30; // typeflag '0' = regular file
|
|
23
|
+
buf.write('ustar\0', 257, 6, 'ascii');
|
|
24
|
+
buf.write('00', 263, 2, 'ascii');
|
|
25
|
+
let sum = 0;
|
|
26
|
+
for (let i = 0; i < 512; i++)
|
|
27
|
+
sum += buf[i];
|
|
28
|
+
// Checksum format: 6 octal digits, null byte, space (8 bytes total)
|
|
29
|
+
const sumStr = sum.toString(8).padStart(6, '0');
|
|
30
|
+
buf.write(sumStr, 148, 6, 'ascii');
|
|
31
|
+
buf[154] = 0x00;
|
|
32
|
+
buf[155] = 0x20;
|
|
33
|
+
return buf;
|
|
34
|
+
}
|
|
35
|
+
export function tarPack(entries) {
|
|
36
|
+
const parts = [];
|
|
37
|
+
for (const e of entries) {
|
|
38
|
+
parts.push(buildHeader(e.name, e.data.length, Math.floor(e.mtimeMs / 1000)));
|
|
39
|
+
parts.push(e.data);
|
|
40
|
+
const padLen = (512 - (e.data.length % 512)) % 512;
|
|
41
|
+
if (padLen > 0)
|
|
42
|
+
parts.push(Buffer.alloc(padLen, 0));
|
|
43
|
+
}
|
|
44
|
+
parts.push(Buffer.alloc(1024, 0)); // end-of-archive: two zero blocks
|
|
45
|
+
return Buffer.concat(parts);
|
|
46
|
+
}
|
|
47
|
+
export function tarUnpack(buf) {
|
|
48
|
+
const entries = [];
|
|
49
|
+
let offset = 0;
|
|
50
|
+
while (offset + 512 <= buf.length) {
|
|
51
|
+
const header = buf.subarray(offset, offset + 512);
|
|
52
|
+
// End-of-archive: a 512-byte zero block
|
|
53
|
+
let allZero = true;
|
|
54
|
+
for (let i = 0; i < 512; i++) {
|
|
55
|
+
if (header[i] !== 0) {
|
|
56
|
+
allZero = false;
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (allZero)
|
|
61
|
+
break;
|
|
62
|
+
const nameRaw = header.toString('utf8', 0, 100);
|
|
63
|
+
const nullIdx = nameRaw.indexOf('\0');
|
|
64
|
+
const name = nullIdx >= 0 ? nameRaw.slice(0, nullIdx) : nameRaw;
|
|
65
|
+
const sizeStr = header.toString('ascii', 124, 136).split('\0')[0].trim();
|
|
66
|
+
const size = parseInt(sizeStr, 8);
|
|
67
|
+
if (!Number.isFinite(size) || size < 0) {
|
|
68
|
+
throw new Error(`tar: bad size field for entry "${name}": ${sizeStr}`);
|
|
69
|
+
}
|
|
70
|
+
offset += 512;
|
|
71
|
+
const data = Buffer.from(buf.subarray(offset, offset + size));
|
|
72
|
+
entries.push({ name, data });
|
|
73
|
+
const padded = Math.ceil(size / 512) * 512;
|
|
74
|
+
offset += padded;
|
|
75
|
+
}
|
|
76
|
+
return entries;
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=tar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tar.js","sourceRoot":"","sources":["../../../src/core/share/tar.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import Database from 'better-sqlite3';
|
|
2
|
+
/**
|
|
3
|
+
* Session user-metadata: freeform tags + custom name override.
|
|
4
|
+
*
|
|
5
|
+
* Stored in the FK-free `session_meta` / `session_tags` tables (migration 0009) so they
|
|
6
|
+
* survive ingest's `INSERT OR REPLACE INTO sessions` cascade. This module owns all reads
|
|
7
|
+
* and writes; server routes stay thin over it.
|
|
8
|
+
*/
|
|
9
|
+
export declare class TagError extends Error {
|
|
10
|
+
readonly status: number;
|
|
11
|
+
constructor(msg: string, status?: number);
|
|
12
|
+
}
|
|
13
|
+
/** Canonical tag form — single source of truth, reused by writes, the filter, and tests. */
|
|
14
|
+
export declare function normalizeTag(raw: string): string;
|
|
15
|
+
export interface SessionMeta {
|
|
16
|
+
/** Resolved display name (precedence applied). */
|
|
17
|
+
name: string;
|
|
18
|
+
/** Raw vyasa override (null if unset) — for the edit field. */
|
|
19
|
+
customName: string | null;
|
|
20
|
+
/** Normalized tags, sorted. */
|
|
21
|
+
tags: string[];
|
|
22
|
+
}
|
|
23
|
+
interface NameRow {
|
|
24
|
+
custom_name: string | null;
|
|
25
|
+
claude_custom_title: string | null;
|
|
26
|
+
claude_ai_title: string | null;
|
|
27
|
+
project: string | null;
|
|
28
|
+
id: string;
|
|
29
|
+
}
|
|
30
|
+
/** Display-name precedence: override → /rename → ai-title → project → short id. */
|
|
31
|
+
export declare function resolveName(row: NameRow): string;
|
|
32
|
+
export declare function setSessionName(db: Database.Database, sessionId: string, name: string | null): void;
|
|
33
|
+
export declare function setTags(db: Database.Database, sessionId: string, tags: string[]): string[];
|
|
34
|
+
/** Restore name + tags from a bundle on import — works even before the session is indexed (FK-free).
|
|
35
|
+
* Defensive: the manifest is an untrusted input (someone else's bundle), so validate field types
|
|
36
|
+
* here rather than trusting them — a bad type must not crash import after the JSONL is already placed. */
|
|
37
|
+
export declare function restoreSessionMeta(db: Database.Database, sessionId: string, meta: {
|
|
38
|
+
customName?: unknown;
|
|
39
|
+
tags?: unknown;
|
|
40
|
+
}): void;
|
|
41
|
+
export declare function getTags(db: Database.Database, sessionId: string): string[];
|
|
42
|
+
export declare function getSessionMeta(db: Database.Database, sessionId: string): SessionMeta;
|
|
43
|
+
export declare function listAllTags(db: Database.Database): Array<{
|
|
44
|
+
tag: string;
|
|
45
|
+
count: number;
|
|
46
|
+
}>;
|
|
47
|
+
export {};
|
|
48
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/tags/index.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAA;AAErC;;;;;;GAMG;AAEH,qBAAa,QAAS,SAAQ,KAAK;IACjC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;gBACX,GAAG,EAAE,MAAM,EAAE,MAAM,SAAM;CAKtC;AAED,4FAA4F;AAC5F,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,MAAM,WAAW,WAAW;IAC1B,kDAAkD;IAClD,IAAI,EAAE,MAAM,CAAA;IACZ,+DAA+D;IAC/D,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,+BAA+B;IAC/B,IAAI,EAAE,MAAM,EAAE,CAAA;CACf;AAED,UAAU,OAAO;IACf,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAA;IAClC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,EAAE,EAAE,MAAM,CAAA;CACX;AAQD,mFAAmF;AACnF,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAQhD;AAOD,wBAAgB,cAAc,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAQlG;AAED,wBAAgB,OAAO,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAG1F;AAcD;;2GAE2G;AAC3G,wBAAgB,kBAAkB,CAChC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE;IAAE,UAAU,CAAC,EAAE,OAAO,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,GAC7C,IAAI,CAaN;AAED,wBAAgB,OAAO,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,CAG1E;AAED,wBAAgB,cAAc,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,SAAS,EAAE,MAAM,GAAG,WAAW,CAuBpF;AAED,wBAAgB,WAAW,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,KAAK,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAIxF"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session user-metadata: freeform tags + custom name override.
|
|
3
|
+
*
|
|
4
|
+
* Stored in the FK-free `session_meta` / `session_tags` tables (migration 0009) so they
|
|
5
|
+
* survive ingest's `INSERT OR REPLACE INTO sessions` cascade. This module owns all reads
|
|
6
|
+
* and writes; server routes stay thin over it.
|
|
7
|
+
*/
|
|
8
|
+
export class TagError extends Error {
|
|
9
|
+
status;
|
|
10
|
+
constructor(msg, status = 400) {
|
|
11
|
+
super(msg);
|
|
12
|
+
this.name = 'TagError';
|
|
13
|
+
this.status = status;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
/** Canonical tag form — single source of truth, reused by writes, the filter, and tests. */
|
|
17
|
+
export function normalizeTag(raw) {
|
|
18
|
+
return raw.trim().toLowerCase().replace(/\s+/g, ' ');
|
|
19
|
+
}
|
|
20
|
+
const truthy = (s) => {
|
|
21
|
+
if (typeof s !== 'string')
|
|
22
|
+
return null;
|
|
23
|
+
const t = s.trim();
|
|
24
|
+
return t.length > 0 ? s : null;
|
|
25
|
+
};
|
|
26
|
+
/** Display-name precedence: override → /rename → ai-title → project → short id. */
|
|
27
|
+
export function resolveName(row) {
|
|
28
|
+
return (truthy(row.custom_name) ??
|
|
29
|
+
truthy(row.claude_custom_title) ??
|
|
30
|
+
truthy(row.claude_ai_title) ??
|
|
31
|
+
truthy(row.project) ??
|
|
32
|
+
row.id.slice(0, 8));
|
|
33
|
+
}
|
|
34
|
+
function assertSessionExists(db, sessionId) {
|
|
35
|
+
const row = db.prepare('SELECT 1 FROM sessions WHERE id = ?').get(sessionId);
|
|
36
|
+
if (!row)
|
|
37
|
+
throw new TagError(`session not found: ${sessionId}`, 404);
|
|
38
|
+
}
|
|
39
|
+
export function setSessionName(db, sessionId, name) {
|
|
40
|
+
assertSessionExists(db, sessionId);
|
|
41
|
+
const value = name != null && name.trim().length > 0 ? name.trim() : null;
|
|
42
|
+
db.prepare(`
|
|
43
|
+
INSERT INTO session_meta (session_id, custom_name)
|
|
44
|
+
VALUES (?, ?)
|
|
45
|
+
ON CONFLICT(session_id) DO UPDATE SET custom_name = excluded.custom_name, updated_at = datetime('now')
|
|
46
|
+
`).run(sessionId, value);
|
|
47
|
+
}
|
|
48
|
+
export function setTags(db, sessionId, tags) {
|
|
49
|
+
assertSessionExists(db, sessionId);
|
|
50
|
+
return writeTags(db, sessionId, tags);
|
|
51
|
+
}
|
|
52
|
+
/** Shared tag-write (no existence check) used by setTags + restoreSessionMeta. */
|
|
53
|
+
function writeTags(db, sessionId, tags) {
|
|
54
|
+
const normalized = Array.from(new Set(tags.map(normalizeTag).filter((t) => t.length > 0))).sort();
|
|
55
|
+
const del = db.prepare('DELETE FROM session_tags WHERE session_id = ?');
|
|
56
|
+
const ins = db.prepare('INSERT OR IGNORE INTO session_tags (session_id, tag) VALUES (?, ?)');
|
|
57
|
+
db.transaction(() => {
|
|
58
|
+
del.run(sessionId);
|
|
59
|
+
for (const tag of normalized)
|
|
60
|
+
ins.run(sessionId, tag);
|
|
61
|
+
})();
|
|
62
|
+
return normalized;
|
|
63
|
+
}
|
|
64
|
+
/** Restore name + tags from a bundle on import — works even before the session is indexed (FK-free).
|
|
65
|
+
* Defensive: the manifest is an untrusted input (someone else's bundle), so validate field types
|
|
66
|
+
* here rather than trusting them — a bad type must not crash import after the JSONL is already placed. */
|
|
67
|
+
export function restoreSessionMeta(db, sessionId, meta) {
|
|
68
|
+
const name = typeof meta.customName === 'string' && meta.customName.trim().length > 0
|
|
69
|
+
? meta.customName.trim()
|
|
70
|
+
: null;
|
|
71
|
+
if (name) {
|
|
72
|
+
db.prepare(`
|
|
73
|
+
INSERT INTO session_meta (session_id, custom_name)
|
|
74
|
+
VALUES (?, ?)
|
|
75
|
+
ON CONFLICT(session_id) DO UPDATE SET custom_name = excluded.custom_name, updated_at = datetime('now')
|
|
76
|
+
`).run(sessionId, name);
|
|
77
|
+
}
|
|
78
|
+
const tags = Array.isArray(meta.tags) ? meta.tags.filter((t) => typeof t === 'string') : [];
|
|
79
|
+
if (tags.length > 0)
|
|
80
|
+
writeTags(db, sessionId, tags);
|
|
81
|
+
}
|
|
82
|
+
export function getTags(db, sessionId) {
|
|
83
|
+
return db.prepare('SELECT tag FROM session_tags WHERE session_id = ? ORDER BY tag').all(sessionId)
|
|
84
|
+
.map((r) => r.tag);
|
|
85
|
+
}
|
|
86
|
+
export function getSessionMeta(db, sessionId) {
|
|
87
|
+
const row = db.prepare(`
|
|
88
|
+
SELECT s.id AS id, s.project AS project,
|
|
89
|
+
m.custom_name AS custom_name, m.claude_custom_title AS claude_custom_title, m.claude_ai_title AS claude_ai_title
|
|
90
|
+
FROM sessions s LEFT JOIN session_meta m ON m.session_id = s.id
|
|
91
|
+
WHERE s.id = ?
|
|
92
|
+
`).get(sessionId);
|
|
93
|
+
// Session may not be indexed yet (e.g. just-imported bundle) — fall back to the meta row alone.
|
|
94
|
+
if (!row) {
|
|
95
|
+
const m = db.prepare('SELECT custom_name, claude_custom_title, claude_ai_title FROM session_meta WHERE session_id = ?')
|
|
96
|
+
.get(sessionId);
|
|
97
|
+
const nameRow = {
|
|
98
|
+
custom_name: m?.custom_name ?? null,
|
|
99
|
+
claude_custom_title: m?.claude_custom_title ?? null,
|
|
100
|
+
claude_ai_title: m?.claude_ai_title ?? null,
|
|
101
|
+
project: null,
|
|
102
|
+
id: sessionId,
|
|
103
|
+
};
|
|
104
|
+
return { name: resolveName(nameRow), customName: nameRow.custom_name, tags: getTags(db, sessionId) };
|
|
105
|
+
}
|
|
106
|
+
return { name: resolveName(row), customName: row.custom_name, tags: getTags(db, sessionId) };
|
|
107
|
+
}
|
|
108
|
+
export function listAllTags(db) {
|
|
109
|
+
return db.prepare(`
|
|
110
|
+
SELECT tag, COUNT(*) AS count FROM session_tags GROUP BY tag ORDER BY count DESC, tag ASC
|
|
111
|
+
`).all();
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/tags/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import Database from 'better-sqlite3';
|
|
2
|
+
export interface SessionWasteSummary {
|
|
3
|
+
sessionId: string;
|
|
4
|
+
project: string;
|
|
5
|
+
costCents: number;
|
|
6
|
+
/** Total tokens this session (input + output + cache) — the nudge leads with this, not dollars. */
|
|
7
|
+
tokens: number;
|
|
8
|
+
totalWasteCents: number;
|
|
9
|
+
/** Largest single waste cause for this session, or null if none. */
|
|
10
|
+
top: {
|
|
11
|
+
category: string;
|
|
12
|
+
amountCents: number;
|
|
13
|
+
anchorMsgIdx: number | null;
|
|
14
|
+
cause: string;
|
|
15
|
+
} | null;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Per-session waste rollup. Reads the persisted `waste_attributions` (populated by
|
|
19
|
+
* computeAllWaste), so run computeAllWaste first if you need fresh numbers.
|
|
20
|
+
*
|
|
21
|
+
* Shared by the terminal nudge and (Phase 3a) the Today view — single source of
|
|
22
|
+
* truth so the nudge and the dashboard never disagree.
|
|
23
|
+
*/
|
|
24
|
+
export declare function summarizeSessionWaste(db: Database.Database, sessionId: string): SessionWasteSummary | null;
|
|
25
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/today/index.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAA;AAErC,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;IACjB,mGAAmG;IACnG,MAAM,EAAE,MAAM,CAAA;IACd,eAAe,EAAE,MAAM,CAAA;IACvB,oEAAoE;IACpE,GAAG,EAAE;QACH,QAAQ,EAAE,MAAM,CAAA;QAChB,WAAW,EAAE,MAAM,CAAA;QACnB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;QAC3B,KAAK,EAAE,MAAM,CAAA;KACd,GAAG,IAAI,CAAA;CACT;AASD;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,SAAS,EAAE,MAAM,GAAG,mBAAmB,GAAG,IAAI,CA+B1G"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// Plain-language cause labels for the terminal nudge (no jargon — swarm feedback).
|
|
2
|
+
const CAUSE = {
|
|
3
|
+
'cache-miss': 'low cache reuse',
|
|
4
|
+
'wrong-model': 'Opus on a simple task',
|
|
5
|
+
abandoned: 'abandoned mid-task',
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Per-session waste rollup. Reads the persisted `waste_attributions` (populated by
|
|
9
|
+
* computeAllWaste), so run computeAllWaste first if you need fresh numbers.
|
|
10
|
+
*
|
|
11
|
+
* Shared by the terminal nudge and (Phase 3a) the Today view — single source of
|
|
12
|
+
* truth so the nudge and the dashboard never disagree.
|
|
13
|
+
*/
|
|
14
|
+
export function summarizeSessionWaste(db, sessionId) {
|
|
15
|
+
const s = db
|
|
16
|
+
.prepare(`SELECT id, project, total_cost_cents,
|
|
17
|
+
(total_input_tokens + total_output_tokens + total_cache_creation + total_cache_read) AS tokens
|
|
18
|
+
FROM sessions WHERE id = ?`)
|
|
19
|
+
.get(sessionId);
|
|
20
|
+
if (!s)
|
|
21
|
+
return null;
|
|
22
|
+
const rows = db
|
|
23
|
+
.prepare(`SELECT category, amount_cents, anchor_msg_idx
|
|
24
|
+
FROM waste_attributions WHERE session_id = ?
|
|
25
|
+
ORDER BY amount_cents DESC`)
|
|
26
|
+
.all(sessionId);
|
|
27
|
+
// Categories overlap (an abandoned session's whole cost already includes any
|
|
28
|
+
// cache-miss/wrong-model overpay within it), so the naive sum can exceed what
|
|
29
|
+
// was actually spent. Cap at session cost — you can never waste more than you paid.
|
|
30
|
+
const rawSum = rows.reduce((acc, r) => acc + r.amount_cents, 0);
|
|
31
|
+
const totalWasteCents = Math.min(rawSum, s.total_cost_cents);
|
|
32
|
+
const top = rows[0]
|
|
33
|
+
? {
|
|
34
|
+
category: rows[0].category,
|
|
35
|
+
amountCents: rows[0].amount_cents,
|
|
36
|
+
anchorMsgIdx: rows[0].anchor_msg_idx,
|
|
37
|
+
cause: CAUSE[rows[0].category] ?? rows[0].category,
|
|
38
|
+
}
|
|
39
|
+
: null;
|
|
40
|
+
return { sessionId, project: s.project, costCents: s.total_cost_cents, tokens: s.tokens ?? 0, totalWasteCents, top };
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/today/index.ts"],"names":[],"mappings":"AAkBA,mFAAmF;AACnF,MAAM,KAAK,GAA2B;IACpC,YAAY,EAAE,iBAAiB;IAC/B,aAAa,EAAE,uBAAuB;IACtC,SAAS,EAAE,oBAAoB;CAChC,CAAA;AAED;;;;;;GAMG;AACH,MAAM,UAAU,qBAAqB,CAAC,EAAqB,EAAE,SAAiB;IAC5E,MAAM,CAAC,GAAG,EAAE;SACT,OAAO,CAAC;;yCAE4B,CAAC;SACrC,GAAG,CAAC,SAAS,CAA0F,CAAA;IAC1G,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAA;IAEnB,MAAM,IAAI,GAAG,EAAE;SACZ,OAAO,CACN;;kCAE4B,CAC7B;SACA,GAAG,CAAC,SAAS,CAAqF,CAAA;IAErG,6EAA6E;IAC7E,8EAA8E;IAC9E,oFAAoF;IACpF,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,CAAA;IAC/D,MAAM,eAAe,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,gBAAgB,CAAC,CAAA;IAC5D,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC;QACjB,CAAC,CAAC;YACE,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ;YAC1B,WAAW,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,YAAY;YACjC,YAAY,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,cAAc;YACpC,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ;SACnD;QACH,CAAC,CAAC,IAAI,CAAA;IAER,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,SAAS,EAAE,CAAC,CAAC,gBAAgB,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,IAAI,CAAC,EAAE,eAAe,EAAE,GAAG,EAAE,CAAA;AACtH,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import Database from 'better-sqlite3';
|
|
2
|
+
import type { WasteAttribution } from '../schema/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* Detects two sub-cases of abandoned sessions:
|
|
5
|
+
* A) Short sessions (≤ 60s) with no resumption in the same project within 24h.
|
|
6
|
+
* B) Sessions where the last assistant message has a pending tool_use but no
|
|
7
|
+
* subsequent user message with a tool_result.
|
|
8
|
+
*
|
|
9
|
+
* Sub-case B takes precedence over A if both match.
|
|
10
|
+
*/
|
|
11
|
+
export declare function detectAbandoned(db: Database.Database): WasteAttribution[];
|
|
12
|
+
//# sourceMappingURL=abandoned.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"abandoned.d.ts","sourceRoot":"","sources":["../../../src/core/waste/abandoned.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAA;AACrC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAoD1D;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,gBAAgB,EAAE,CAkGzE"}
|