@tyroneross/bookmark 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/.claude-plugin/marketplace.json +15 -0
- package/.claude-plugin/plugin.json +13 -0
- package/CLAUDE.md +69 -0
- package/LICENSE +21 -0
- package/README.md +178 -0
- package/agents/snapshot-analyst.md +41 -0
- package/commands/activate.md +20 -0
- package/commands/list.md +15 -0
- package/commands/restore.md +30 -0
- package/commands/snapshot.md +26 -0
- package/commands/status.md +19 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +437 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/config.d.ts +5 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +86 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/restore/index.d.ts +13 -0
- package/dist/restore/index.d.ts.map +1 -0
- package/dist/restore/index.js +94 -0
- package/dist/restore/index.js.map +1 -0
- package/dist/setup/auto-setup.d.ts +16 -0
- package/dist/setup/auto-setup.d.ts.map +1 -0
- package/dist/setup/auto-setup.js +192 -0
- package/dist/setup/auto-setup.js.map +1 -0
- package/dist/setup/configure-hooks.d.ts +10 -0
- package/dist/setup/configure-hooks.d.ts.map +1 -0
- package/dist/setup/configure-hooks.js +97 -0
- package/dist/setup/configure-hooks.js.map +1 -0
- package/dist/snapshot/capture.d.ts +21 -0
- package/dist/snapshot/capture.d.ts.map +1 -0
- package/dist/snapshot/capture.js +134 -0
- package/dist/snapshot/capture.js.map +1 -0
- package/dist/snapshot/compress.d.ts +8 -0
- package/dist/snapshot/compress.d.ts.map +1 -0
- package/dist/snapshot/compress.js +93 -0
- package/dist/snapshot/compress.js.map +1 -0
- package/dist/snapshot/storage.d.ts +13 -0
- package/dist/snapshot/storage.d.ts.map +1 -0
- package/dist/snapshot/storage.js +151 -0
- package/dist/snapshot/storage.js.map +1 -0
- package/dist/threshold/adaptive.d.ts +23 -0
- package/dist/threshold/adaptive.d.ts.map +1 -0
- package/dist/threshold/adaptive.js +29 -0
- package/dist/threshold/adaptive.js.map +1 -0
- package/dist/threshold/state.d.ts +8 -0
- package/dist/threshold/state.d.ts.map +1 -0
- package/dist/threshold/state.js +83 -0
- package/dist/threshold/state.js.map +1 -0
- package/dist/threshold/time-based.d.ts +13 -0
- package/dist/threshold/time-based.d.ts.map +1 -0
- package/dist/threshold/time-based.js +24 -0
- package/dist/threshold/time-based.js.map +1 -0
- package/dist/transcript/estimator.d.ts +20 -0
- package/dist/transcript/estimator.d.ts.map +1 -0
- package/dist/transcript/estimator.js +95 -0
- package/dist/transcript/estimator.js.map +1 -0
- package/dist/transcript/extractor.d.ts +7 -0
- package/dist/transcript/extractor.d.ts.map +1 -0
- package/dist/transcript/extractor.js +237 -0
- package/dist/transcript/extractor.js.map +1 -0
- package/dist/transcript/parser.d.ts +16 -0
- package/dist/transcript/parser.d.ts.map +1 -0
- package/dist/transcript/parser.js +120 -0
- package/dist/transcript/parser.js.map +1 -0
- package/dist/types.d.ts +156 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/hooks/hooks.json +54 -0
- package/package.json +77 -0
- package/scripts/install-plugin.sh +38 -0
- package/skills/context-continuity/SKILL.md +49 -0
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compress a full snapshot into a concise markdown summary.
|
|
3
|
+
* Target: <150 lines, <1000 tokens.
|
|
4
|
+
* This becomes LATEST.md — the hot context tier.
|
|
5
|
+
*/
|
|
6
|
+
export function compressToMarkdown(snapshot) {
|
|
7
|
+
const lines = [];
|
|
8
|
+
// Header
|
|
9
|
+
const date = new Date(snapshot.timestamp).toISOString();
|
|
10
|
+
lines.push(`# Session Context - Last Updated ${date}`);
|
|
11
|
+
lines.push('');
|
|
12
|
+
lines.push(`> Snapshot: ${snapshot.snapshot_id} | Compaction cycle: ${snapshot.compaction_cycle} | Trigger: ${snapshot.trigger}`);
|
|
13
|
+
lines.push(`> Context remaining: ${Math.round(snapshot.context_remaining_pct * 100)}% (~${snapshot.token_estimate.toLocaleString()} tokens used)`);
|
|
14
|
+
lines.push('');
|
|
15
|
+
// Current Status
|
|
16
|
+
if (snapshot.current_status && snapshot.current_status !== 'No status available') {
|
|
17
|
+
lines.push('## Current Status');
|
|
18
|
+
lines.push(truncate(snapshot.current_status, 300));
|
|
19
|
+
lines.push('');
|
|
20
|
+
}
|
|
21
|
+
// Decisions
|
|
22
|
+
if (snapshot.decisions.length > 0) {
|
|
23
|
+
lines.push('## Decisions Made');
|
|
24
|
+
for (const d of snapshot.decisions.slice(0, 8)) {
|
|
25
|
+
const rationale = d.rationale ? ` (${truncate(d.rationale, 80)})` : '';
|
|
26
|
+
lines.push(`- ${truncate(d.description, 150)}${rationale}`);
|
|
27
|
+
}
|
|
28
|
+
if (snapshot.decisions.length > 8) {
|
|
29
|
+
lines.push(`- ...and ${snapshot.decisions.length - 8} more`);
|
|
30
|
+
}
|
|
31
|
+
lines.push('');
|
|
32
|
+
}
|
|
33
|
+
// Files Changed
|
|
34
|
+
if (snapshot.files_changed.length > 0) {
|
|
35
|
+
lines.push('## Files Changed This Session');
|
|
36
|
+
for (const f of snapshot.files_changed.slice(0, 12)) {
|
|
37
|
+
const ops = f.operations.join(', ');
|
|
38
|
+
lines.push(`- \`${f.path}\` (${ops})`);
|
|
39
|
+
}
|
|
40
|
+
if (snapshot.files_changed.length > 12) {
|
|
41
|
+
lines.push(`- ...and ${snapshot.files_changed.length - 12} more files`);
|
|
42
|
+
}
|
|
43
|
+
lines.push('');
|
|
44
|
+
}
|
|
45
|
+
// Open Items
|
|
46
|
+
if (snapshot.open_items.length > 0) {
|
|
47
|
+
lines.push('## Open Items');
|
|
48
|
+
for (const item of snapshot.open_items.slice(0, 8)) {
|
|
49
|
+
const priority = item.priority === 'high' ? ' [HIGH]' : item.priority === 'medium' ? ' [MED]' : '';
|
|
50
|
+
lines.push(`- [ ] ${truncate(item.description, 150)}${priority}`);
|
|
51
|
+
}
|
|
52
|
+
if (snapshot.open_items.length > 8) {
|
|
53
|
+
lines.push(`- ...and ${snapshot.open_items.length - 8} more`);
|
|
54
|
+
}
|
|
55
|
+
lines.push('');
|
|
56
|
+
}
|
|
57
|
+
// Unknowns / Blockers
|
|
58
|
+
if (snapshot.unknowns.length > 0) {
|
|
59
|
+
lines.push('## Unknowns / Blockers');
|
|
60
|
+
for (const u of snapshot.unknowns.slice(0, 5)) {
|
|
61
|
+
lines.push(`- ${truncate(u, 150)}`);
|
|
62
|
+
}
|
|
63
|
+
lines.push('');
|
|
64
|
+
}
|
|
65
|
+
// Errors (only unresolved)
|
|
66
|
+
const unresolvedErrors = snapshot.errors_encountered.filter(e => !e.resolved);
|
|
67
|
+
if (unresolvedErrors.length > 0) {
|
|
68
|
+
lines.push('## Unresolved Errors');
|
|
69
|
+
for (const e of unresolvedErrors.slice(0, 3)) {
|
|
70
|
+
const tool = e.tool ? ` (${e.tool})` : '';
|
|
71
|
+
lines.push(`- ${truncate(e.message, 150)}${tool}`);
|
|
72
|
+
}
|
|
73
|
+
lines.push('');
|
|
74
|
+
}
|
|
75
|
+
// Tool Usage Summary (compact)
|
|
76
|
+
if (Object.keys(snapshot.tools_summary).length > 0) {
|
|
77
|
+
const topTools = Object.entries(snapshot.tools_summary)
|
|
78
|
+
.sort((a, b) => b[1] - a[1])
|
|
79
|
+
.slice(0, 5)
|
|
80
|
+
.map(([tool, count]) => `${tool}: ${count}`)
|
|
81
|
+
.join(', ');
|
|
82
|
+
lines.push(`> Tool usage: ${topTools}`);
|
|
83
|
+
lines.push('');
|
|
84
|
+
}
|
|
85
|
+
lines.push('*bookmark — context snapshot*');
|
|
86
|
+
return lines.join('\n');
|
|
87
|
+
}
|
|
88
|
+
function truncate(text, maxLen) {
|
|
89
|
+
if (text.length <= maxLen)
|
|
90
|
+
return text;
|
|
91
|
+
return text.slice(0, maxLen - 3) + '...';
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=compress.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compress.js","sourceRoot":"","sources":["../../src/snapshot/compress.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Snapshot, SnapshotEntry } from '../types.js';
|
|
2
|
+
export declare function getSnapshotsDir(storagePath: string): string;
|
|
3
|
+
export declare function getLatestPath(storagePath: string): string;
|
|
4
|
+
export declare function getIndexPath(storagePath: string): string;
|
|
5
|
+
export declare function ensureStorageDirs(storagePath: string): void;
|
|
6
|
+
export declare function storeSnapshot(storagePath: string, snapshot: Snapshot): string;
|
|
7
|
+
export declare function loadSnapshot(storagePath: string, snapshotId: string): Snapshot | null;
|
|
8
|
+
export declare function loadLatestSnapshot(storagePath: string): Snapshot | null;
|
|
9
|
+
export declare function listSnapshots(storagePath: string, limit?: number): SnapshotEntry[];
|
|
10
|
+
export declare function writeLatestMd(storagePath: string, content: string): void;
|
|
11
|
+
export declare function readLatestMd(storagePath: string): string | null;
|
|
12
|
+
export declare function getSnapshotCount(storagePath: string): number;
|
|
13
|
+
//# sourceMappingURL=storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/snapshot/storage.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAiB,aAAa,EAAE,MAAM,aAAa,CAAC;AAY1E,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAExD;AAED,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAW3D;AAED,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAW7E;AAED,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAcrF;AAED,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAMvE;AAED,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,aAAa,EAAE,CAI9E;AAED,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAGxE;AAED,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQ/D;AAiED,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAQ5D"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync, readdirSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
const INDEX_VERSION = '1.0.0';
|
|
4
|
+
function generateSnapshotId() {
|
|
5
|
+
const now = new Date();
|
|
6
|
+
const pad = (n, len = 2) => String(n).padStart(len, '0');
|
|
7
|
+
const date = `${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}`;
|
|
8
|
+
const time = `${pad(now.getHours())}${pad(now.getMinutes())}${pad(now.getSeconds())}`;
|
|
9
|
+
return `SNAP_${date}_${time}`;
|
|
10
|
+
}
|
|
11
|
+
export function getSnapshotsDir(storagePath) {
|
|
12
|
+
return join(storagePath, 'snapshots');
|
|
13
|
+
}
|
|
14
|
+
export function getLatestPath(storagePath) {
|
|
15
|
+
return join(storagePath, 'LATEST.md');
|
|
16
|
+
}
|
|
17
|
+
export function getIndexPath(storagePath) {
|
|
18
|
+
return join(storagePath, 'index.json');
|
|
19
|
+
}
|
|
20
|
+
export function ensureStorageDirs(storagePath) {
|
|
21
|
+
const dirs = [
|
|
22
|
+
storagePath,
|
|
23
|
+
join(storagePath, 'snapshots'),
|
|
24
|
+
join(storagePath, 'archive'),
|
|
25
|
+
];
|
|
26
|
+
for (const dir of dirs) {
|
|
27
|
+
if (!existsSync(dir)) {
|
|
28
|
+
mkdirSync(dir, { recursive: true });
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export function storeSnapshot(storagePath, snapshot) {
|
|
33
|
+
ensureStorageDirs(storagePath);
|
|
34
|
+
const snapshotId = snapshot.snapshot_id || generateSnapshotId();
|
|
35
|
+
const snapshotPath = join(getSnapshotsDir(storagePath), `${snapshotId}.json`);
|
|
36
|
+
writeFileSync(snapshotPath, JSON.stringify(snapshot, null, 2), 'utf-8');
|
|
37
|
+
// Update index
|
|
38
|
+
updateIndex(storagePath, snapshot);
|
|
39
|
+
return snapshotId;
|
|
40
|
+
}
|
|
41
|
+
export function loadSnapshot(storagePath, snapshotId) {
|
|
42
|
+
// Validate snapshot ID format to prevent path traversal
|
|
43
|
+
if (!/^SNAP_\d{8}_\d{6}$/.test(snapshotId)) {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
const snapshotPath = join(getSnapshotsDir(storagePath), `${snapshotId}.json`);
|
|
47
|
+
if (!existsSync(snapshotPath))
|
|
48
|
+
return null;
|
|
49
|
+
try {
|
|
50
|
+
return JSON.parse(readFileSync(snapshotPath, 'utf-8'));
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
export function loadLatestSnapshot(storagePath) {
|
|
57
|
+
const index = loadIndex(storagePath);
|
|
58
|
+
if (!index || index.snapshots.length === 0)
|
|
59
|
+
return null;
|
|
60
|
+
const latestEntry = index.snapshots[0]; // Most recent first
|
|
61
|
+
return loadSnapshot(storagePath, latestEntry.id);
|
|
62
|
+
}
|
|
63
|
+
export function listSnapshots(storagePath, limit = 10) {
|
|
64
|
+
const index = loadIndex(storagePath);
|
|
65
|
+
if (!index)
|
|
66
|
+
return [];
|
|
67
|
+
return index.snapshots.slice(0, limit);
|
|
68
|
+
}
|
|
69
|
+
export function writeLatestMd(storagePath, content) {
|
|
70
|
+
ensureStorageDirs(storagePath);
|
|
71
|
+
writeFileSync(getLatestPath(storagePath), content, 'utf-8');
|
|
72
|
+
}
|
|
73
|
+
export function readLatestMd(storagePath) {
|
|
74
|
+
const path = getLatestPath(storagePath);
|
|
75
|
+
if (!existsSync(path))
|
|
76
|
+
return null;
|
|
77
|
+
try {
|
|
78
|
+
return readFileSync(path, 'utf-8');
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function loadIndex(storagePath) {
|
|
85
|
+
const indexPath = getIndexPath(storagePath);
|
|
86
|
+
if (!existsSync(indexPath))
|
|
87
|
+
return null;
|
|
88
|
+
try {
|
|
89
|
+
return JSON.parse(readFileSync(indexPath, 'utf-8'));
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
function updateIndex(storagePath, snapshot) {
|
|
96
|
+
const indexPath = getIndexPath(storagePath);
|
|
97
|
+
let index = loadIndex(storagePath) ?? {
|
|
98
|
+
version: INDEX_VERSION,
|
|
99
|
+
project_path: snapshot.project_path,
|
|
100
|
+
last_updated: Date.now(),
|
|
101
|
+
stats: {
|
|
102
|
+
total_snapshots: 0,
|
|
103
|
+
compaction_cycles: 0,
|
|
104
|
+
last_compaction: 0,
|
|
105
|
+
last_snapshot: 0,
|
|
106
|
+
last_time_based: 0,
|
|
107
|
+
},
|
|
108
|
+
snapshots: [],
|
|
109
|
+
};
|
|
110
|
+
const entry = {
|
|
111
|
+
id: snapshot.snapshot_id,
|
|
112
|
+
timestamp: snapshot.timestamp,
|
|
113
|
+
trigger: snapshot.trigger,
|
|
114
|
+
compaction_cycle: snapshot.compaction_cycle,
|
|
115
|
+
context_remaining_pct: snapshot.context_remaining_pct,
|
|
116
|
+
token_estimate: snapshot.token_estimate,
|
|
117
|
+
decisions_count: snapshot.decisions.length,
|
|
118
|
+
files_changed_count: snapshot.files_changed.length,
|
|
119
|
+
open_items_count: snapshot.open_items.length,
|
|
120
|
+
};
|
|
121
|
+
// Add to front (most recent first)
|
|
122
|
+
index.snapshots.unshift(entry);
|
|
123
|
+
// Update stats
|
|
124
|
+
index.stats.total_snapshots = index.snapshots.length;
|
|
125
|
+
index.stats.last_snapshot = snapshot.timestamp;
|
|
126
|
+
index.last_updated = Date.now();
|
|
127
|
+
if (snapshot.trigger === 'pre_compact') {
|
|
128
|
+
index.stats.compaction_cycles = snapshot.compaction_cycle;
|
|
129
|
+
index.stats.last_compaction = snapshot.timestamp;
|
|
130
|
+
}
|
|
131
|
+
if (snapshot.trigger === 'time_interval') {
|
|
132
|
+
index.stats.last_time_based = snapshot.timestamp;
|
|
133
|
+
}
|
|
134
|
+
// Cap active snapshots
|
|
135
|
+
if (index.snapshots.length > 50) {
|
|
136
|
+
index.snapshots.length = 50;
|
|
137
|
+
}
|
|
138
|
+
writeFileSync(indexPath, JSON.stringify(index, null, 2), 'utf-8');
|
|
139
|
+
}
|
|
140
|
+
export function getSnapshotCount(storagePath) {
|
|
141
|
+
const snapshotsDir = getSnapshotsDir(storagePath);
|
|
142
|
+
if (!existsSync(snapshotsDir))
|
|
143
|
+
return 0;
|
|
144
|
+
try {
|
|
145
|
+
return readdirSync(snapshotsDir).filter(f => f.startsWith('SNAP_') && f.endsWith('.json')).length;
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
return 0;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../../src/snapshot/storage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAC1F,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC,MAAM,aAAa,GAAG,OAAO,CAAC;AAE9B,SAAS,kBAAkB;IACzB,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IACvB,MAAM,GAAG,GAAG,CAAC,CAAS,EAAE,GAAG,GAAG,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IACjE,MAAM,IAAI,GAAG,GAAG,GAAG,CAAC,WAAW,EAAE,GAAG,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;IACnF,MAAM,IAAI,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,EAAE,CAAC;IACtF,OAAO,QAAQ,IAAI,IAAI,IAAI,EAAE,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,WAAmB;IACjD,OAAO,IAAI,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,WAAmB;IAC/C,OAAO,IAAI,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,WAAmB;IAC9C,OAAO,IAAI,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;AACzC,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,WAAmB;IACnD,MAAM,IAAI,GAAG;QACX,WAAW;QACX,IAAI,CAAC,WAAW,EAAE,WAAW,CAAC;QAC9B,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC;KAC7B,CAAC;IACF,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACrB,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACtC,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,WAAmB,EAAE,QAAkB;IACnE,iBAAiB,CAAC,WAAW,CAAC,CAAC;IAE/B,MAAM,UAAU,GAAG,QAAQ,CAAC,WAAW,IAAI,kBAAkB,EAAE,CAAC;IAChE,MAAM,YAAY,GAAG,IAAI,CAAC,eAAe,CAAC,WAAW,CAAC,EAAE,GAAG,UAAU,OAAO,CAAC,CAAC;IAC9E,aAAa,CAAC,YAAY,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IAExE,eAAe;IACf,WAAW,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;IAEnC,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,WAAmB,EAAE,UAAkB;IAClE,wDAAwD;IACxD,IAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;QAC3C,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,YAAY,GAAG,IAAI,CAAC,eAAe,CAAC,WAAW,CAAC,EAAE,GAAG,UAAU,OAAO,CAAC,CAAC;IAC9E,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC;QAAE,OAAO,IAAI,CAAC;IAE3C,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAa,CAAC;IACrE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,WAAmB;IACpD,MAAM,KAAK,GAAG,SAAS,CAAC,WAAW,CAAC,CAAC;IACrC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAExD,MAAM,WAAW,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,oBAAoB;IAC5D,OAAO,YAAY,CAAC,WAAW,EAAE,WAAW,CAAC,EAAE,CAAC,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,WAAmB,EAAE,KAAK,GAAG,EAAE;IAC3D,MAAM,KAAK,GAAG,SAAS,CAAC,WAAW,CAAC,CAAC;IACrC,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,CAAC;IACtB,OAAO,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;AACzC,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,WAAmB,EAAE,OAAe;IAChE,iBAAiB,CAAC,WAAW,CAAC,CAAC;IAC/B,aAAa,CAAC,aAAa,CAAC,WAAW,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;AAC9D,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,WAAmB;IAC9C,MAAM,IAAI,GAAG,aAAa,CAAC,WAAW,CAAC,CAAC;IACxC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACnC,IAAI,CAAC;QACH,OAAO,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,SAAS,CAAC,WAAmB;IACpC,MAAM,SAAS,GAAG,YAAY,CAAC,WAAW,CAAC,CAAC;IAC5C,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;QAAE,OAAO,IAAI,CAAC;IACxC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAkB,CAAC;IACvE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,WAAW,CAAC,WAAmB,EAAE,QAAkB;IAC1D,MAAM,SAAS,GAAG,YAAY,CAAC,WAAW,CAAC,CAAC;IAE5C,IAAI,KAAK,GAAkB,SAAS,CAAC,WAAW,CAAC,IAAI;QACnD,OAAO,EAAE,aAAa;QACtB,YAAY,EAAE,QAAQ,CAAC,YAAY;QACnC,YAAY,EAAE,IAAI,CAAC,GAAG,EAAE;QACxB,KAAK,EAAE;YACL,eAAe,EAAE,CAAC;YAClB,iBAAiB,EAAE,CAAC;YACpB,eAAe,EAAE,CAAC;YAClB,aAAa,EAAE,CAAC;YAChB,eAAe,EAAE,CAAC;SACnB;QACD,SAAS,EAAE,EAAE;KACd,CAAC;IAEF,MAAM,KAAK,GAAkB;QAC3B,EAAE,EAAE,QAAQ,CAAC,WAAW;QACxB,SAAS,EAAE,QAAQ,CAAC,SAAS;QAC7B,OAAO,EAAE,QAAQ,CAAC,OAAO;QACzB,gBAAgB,EAAE,QAAQ,CAAC,gBAAgB;QAC3C,qBAAqB,EAAE,QAAQ,CAAC,qBAAqB;QACrD,cAAc,EAAE,QAAQ,CAAC,cAAc;QACvC,eAAe,EAAE,QAAQ,CAAC,SAAS,CAAC,MAAM;QAC1C,mBAAmB,EAAE,QAAQ,CAAC,aAAa,CAAC,MAAM;QAClD,gBAAgB,EAAE,QAAQ,CAAC,UAAU,CAAC,MAAM;KAC7C,CAAC;IAEF,mCAAmC;IACnC,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAE/B,eAAe;IACf,KAAK,CAAC,KAAK,CAAC,eAAe,GAAG,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC;IACrD,KAAK,CAAC,KAAK,CAAC,aAAa,GAAG,QAAQ,CAAC,SAAS,CAAC;IAC/C,KAAK,CAAC,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAEhC,IAAI,QAAQ,CAAC,OAAO,KAAK,aAAa,EAAE,CAAC;QACvC,KAAK,CAAC,KAAK,CAAC,iBAAiB,GAAG,QAAQ,CAAC,gBAAgB,CAAC;QAC1D,KAAK,CAAC,KAAK,CAAC,eAAe,GAAG,QAAQ,CAAC,SAAS,CAAC;IACnD,CAAC;IACD,IAAI,QAAQ,CAAC,OAAO,KAAK,eAAe,EAAE,CAAC;QACzC,KAAK,CAAC,KAAK,CAAC,eAAe,GAAG,QAAQ,CAAC,SAAS,CAAC;IACnD,CAAC;IAED,uBAAuB;IACvB,IAAI,KAAK,CAAC,SAAS,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;QAChC,KAAK,CAAC,SAAS,CAAC,MAAM,GAAG,EAAE,CAAC;IAC9B,CAAC;IAED,aAAa,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;AACpE,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,WAAmB;IAClD,MAAM,YAAY,GAAG,eAAe,CAAC,WAAW,CAAC,CAAC;IAClD,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC;QAAE,OAAO,CAAC,CAAC;IACxC,IAAI,CAAC;QACH,OAAO,WAAW,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC;IACpG,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,CAAC;IACX,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { BookmarkConfig } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Get the current snapshot threshold based on compaction count.
|
|
4
|
+
*
|
|
5
|
+
* As compaction happens more frequently, snapshot earlier:
|
|
6
|
+
* - 0 compactions: snapshot when 20% context remains
|
|
7
|
+
* - 1 compaction: snapshot when 30% context remains
|
|
8
|
+
* - 2 compactions: snapshot when 40% context remains
|
|
9
|
+
* - 3+ compactions: snapshot when 50% context remains (capped)
|
|
10
|
+
*
|
|
11
|
+
* @returns threshold as a fraction (0.0-1.0) representing % context remaining
|
|
12
|
+
*/
|
|
13
|
+
export declare function getThreshold(compactionCount: number, config: BookmarkConfig): number;
|
|
14
|
+
/**
|
|
15
|
+
* Check if current context usage should trigger a snapshot.
|
|
16
|
+
*
|
|
17
|
+
* @param remainingPct - fraction of context remaining (0.0-1.0)
|
|
18
|
+
* @param compactionCount - number of compactions in this session chain
|
|
19
|
+
* @param config - bookmark configuration
|
|
20
|
+
* @returns true if a snapshot should be taken
|
|
21
|
+
*/
|
|
22
|
+
export declare function shouldSnapshotByThreshold(remainingPct: number, compactionCount: number, config: BookmarkConfig): boolean;
|
|
23
|
+
//# sourceMappingURL=adaptive.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adaptive.d.ts","sourceRoot":"","sources":["../../src/threshold/adaptive.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,eAAe,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,GAAG,MAAM,CAIpF;AAED;;;;;;;GAOG;AACH,wBAAgB,yBAAyB,CACvC,YAAY,EAAE,MAAM,EACpB,eAAe,EAAE,MAAM,EACvB,MAAM,EAAE,cAAc,GACrB,OAAO,CAGT"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get the current snapshot threshold based on compaction count.
|
|
3
|
+
*
|
|
4
|
+
* As compaction happens more frequently, snapshot earlier:
|
|
5
|
+
* - 0 compactions: snapshot when 20% context remains
|
|
6
|
+
* - 1 compaction: snapshot when 30% context remains
|
|
7
|
+
* - 2 compactions: snapshot when 40% context remains
|
|
8
|
+
* - 3+ compactions: snapshot when 50% context remains (capped)
|
|
9
|
+
*
|
|
10
|
+
* @returns threshold as a fraction (0.0-1.0) representing % context remaining
|
|
11
|
+
*/
|
|
12
|
+
export function getThreshold(compactionCount, config) {
|
|
13
|
+
const { thresholds, maxThreshold } = config;
|
|
14
|
+
const index = Math.min(compactionCount, thresholds.length - 1);
|
|
15
|
+
return Math.min(thresholds[index], maxThreshold);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Check if current context usage should trigger a snapshot.
|
|
19
|
+
*
|
|
20
|
+
* @param remainingPct - fraction of context remaining (0.0-1.0)
|
|
21
|
+
* @param compactionCount - number of compactions in this session chain
|
|
22
|
+
* @param config - bookmark configuration
|
|
23
|
+
* @returns true if a snapshot should be taken
|
|
24
|
+
*/
|
|
25
|
+
export function shouldSnapshotByThreshold(remainingPct, compactionCount, config) {
|
|
26
|
+
const threshold = getThreshold(compactionCount, config);
|
|
27
|
+
return remainingPct <= threshold;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=adaptive.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adaptive.js","sourceRoot":"","sources":["../../src/threshold/adaptive.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;GAUG;AACH,MAAM,UAAU,YAAY,CAAC,eAAuB,EAAE,MAAsB;IAC1E,MAAM,EAAE,UAAU,EAAE,YAAY,EAAE,GAAG,MAAM,CAAC;IAC5C,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,eAAe,EAAE,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC/D,OAAO,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,YAAY,CAAC,CAAC;AACnD,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,yBAAyB,CACvC,YAAoB,EACpB,eAAuB,EACvB,MAAsB;IAEtB,MAAM,SAAS,GAAG,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC;IACxD,OAAO,YAAY,IAAI,SAAS,CAAC;AACnC,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { BookmarkState } from '../types.js';
|
|
2
|
+
export declare function getStatePath(storagePath: string): string;
|
|
3
|
+
export declare function loadState(storagePath: string): BookmarkState;
|
|
4
|
+
export declare function saveState(storagePath: string, state: BookmarkState): void;
|
|
5
|
+
export declare function incrementCompaction(state: BookmarkState, thresholds: number[]): BookmarkState;
|
|
6
|
+
export declare function resetForNewSession(state: BookmarkState, sessionId: string, thresholds: number[]): BookmarkState;
|
|
7
|
+
export declare function updateSnapshotTime(state: BookmarkState): BookmarkState;
|
|
8
|
+
//# sourceMappingURL=state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../src/threshold/state.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAgB,MAAM,aAAa,CAAC;AAkB/D,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAExD;AAED,wBAAgB,SAAS,CAAC,WAAW,EAAE,MAAM,GAAG,aAAa,CAY5D;AAED,wBAAgB,SAAS,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,IAAI,CAOzE;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,aAAa,CAQ7F;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,aAAa,CAyB/G;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,aAAa,GAAG,aAAa,CAMtE"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';
|
|
2
|
+
import { join, dirname } from 'node:path';
|
|
3
|
+
const STATE_VERSION = '1.0.0';
|
|
4
|
+
const MAX_SESSION_HISTORY = 10;
|
|
5
|
+
function defaultState() {
|
|
6
|
+
return {
|
|
7
|
+
version: STATE_VERSION,
|
|
8
|
+
session_id: '',
|
|
9
|
+
compaction_count: 0,
|
|
10
|
+
current_threshold: 0.20,
|
|
11
|
+
last_snapshot_time: 0,
|
|
12
|
+
last_event_time: 0,
|
|
13
|
+
snapshot_interval_minutes: 20,
|
|
14
|
+
session_history: [],
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export function getStatePath(storagePath) {
|
|
18
|
+
return join(storagePath, 'state.json');
|
|
19
|
+
}
|
|
20
|
+
export function loadState(storagePath) {
|
|
21
|
+
const statePath = getStatePath(storagePath);
|
|
22
|
+
if (!existsSync(statePath)) {
|
|
23
|
+
return defaultState();
|
|
24
|
+
}
|
|
25
|
+
try {
|
|
26
|
+
const raw = readFileSync(statePath, 'utf-8');
|
|
27
|
+
const parsed = JSON.parse(raw);
|
|
28
|
+
return { ...defaultState(), ...parsed };
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return defaultState();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export function saveState(storagePath, state) {
|
|
35
|
+
const statePath = getStatePath(storagePath);
|
|
36
|
+
const dir = dirname(statePath);
|
|
37
|
+
if (!existsSync(dir)) {
|
|
38
|
+
mkdirSync(dir, { recursive: true });
|
|
39
|
+
}
|
|
40
|
+
writeFileSync(statePath, JSON.stringify(state, null, 2), 'utf-8');
|
|
41
|
+
}
|
|
42
|
+
export function incrementCompaction(state, thresholds) {
|
|
43
|
+
const newCount = state.compaction_count + 1;
|
|
44
|
+
const thresholdIndex = Math.min(newCount, thresholds.length - 1);
|
|
45
|
+
return {
|
|
46
|
+
...state,
|
|
47
|
+
compaction_count: newCount,
|
|
48
|
+
current_threshold: thresholds[thresholdIndex],
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
export function resetForNewSession(state, sessionId, thresholds) {
|
|
52
|
+
// Archive current session if it has data
|
|
53
|
+
const history = [...state.session_history];
|
|
54
|
+
if (state.session_id) {
|
|
55
|
+
const currentEntry = {
|
|
56
|
+
session_id: state.session_id,
|
|
57
|
+
started: state.session_history.find(s => s.session_id === state.session_id)?.started ?? state.last_event_time,
|
|
58
|
+
ended: Date.now(),
|
|
59
|
+
compaction_count: state.compaction_count,
|
|
60
|
+
snapshots_taken: 0, // Updated elsewhere
|
|
61
|
+
};
|
|
62
|
+
history.unshift(currentEntry);
|
|
63
|
+
if (history.length > MAX_SESSION_HISTORY) {
|
|
64
|
+
history.length = MAX_SESSION_HISTORY;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
...state,
|
|
69
|
+
session_id: sessionId,
|
|
70
|
+
compaction_count: 0,
|
|
71
|
+
current_threshold: thresholds[0],
|
|
72
|
+
last_event_time: Date.now(),
|
|
73
|
+
session_history: history,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
export function updateSnapshotTime(state) {
|
|
77
|
+
return {
|
|
78
|
+
...state,
|
|
79
|
+
last_snapshot_time: Date.now(),
|
|
80
|
+
last_event_time: Date.now(),
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/threshold/state.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { BookmarkState } from '../types.js';
|
|
2
|
+
export interface TimeCheckResult {
|
|
3
|
+
shouldSnapshot: boolean;
|
|
4
|
+
elapsedMinutes: number;
|
|
5
|
+
intervalMinutes: number;
|
|
6
|
+
reason?: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Check if the time-based snapshot interval has elapsed.
|
|
10
|
+
* Piggybacks on UserPromptSubmit events — no timer needed.
|
|
11
|
+
*/
|
|
12
|
+
export declare function checkTimeInterval(state: BookmarkState): TimeCheckResult;
|
|
13
|
+
//# sourceMappingURL=time-based.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"time-based.d.ts","sourceRoot":"","sources":["../../src/threshold/time-based.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,MAAM,WAAW,eAAe;IAC9B,cAAc,EAAE,OAAO,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,aAAa,GAAG,eAAe,CAoBvE"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Check if the time-based snapshot interval has elapsed.
|
|
3
|
+
* Piggybacks on UserPromptSubmit events — no timer needed.
|
|
4
|
+
*/
|
|
5
|
+
export function checkTimeInterval(state) {
|
|
6
|
+
const now = Date.now();
|
|
7
|
+
const intervalMs = state.snapshot_interval_minutes * 60 * 1000;
|
|
8
|
+
const elapsed = now - (state.last_snapshot_time || now);
|
|
9
|
+
const elapsedMinutes = Math.floor(elapsed / 60_000);
|
|
10
|
+
if (state.last_snapshot_time > 0 && elapsed >= intervalMs) {
|
|
11
|
+
return {
|
|
12
|
+
shouldSnapshot: true,
|
|
13
|
+
elapsedMinutes,
|
|
14
|
+
intervalMinutes: state.snapshot_interval_minutes,
|
|
15
|
+
reason: `${elapsedMinutes}min since last snapshot (interval: ${state.snapshot_interval_minutes}min)`,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
return {
|
|
19
|
+
shouldSnapshot: false,
|
|
20
|
+
elapsedMinutes,
|
|
21
|
+
intervalMinutes: state.snapshot_interval_minutes,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=time-based.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"time-based.js","sourceRoot":"","sources":["../../src/threshold/time-based.ts"],"names":[],"mappings":"AASA;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAoB;IACpD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,MAAM,UAAU,GAAG,KAAK,CAAC,yBAAyB,GAAG,EAAE,GAAG,IAAI,CAAC;IAC/D,MAAM,OAAO,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,kBAAkB,IAAI,GAAG,CAAC,CAAC;IACxD,MAAM,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC,CAAC;IAEpD,IAAI,KAAK,CAAC,kBAAkB,GAAG,CAAC,IAAI,OAAO,IAAI,UAAU,EAAE,CAAC;QAC1D,OAAO;YACL,cAAc,EAAE,IAAI;YACpB,cAAc;YACd,eAAe,EAAE,KAAK,CAAC,yBAAyB;YAChD,MAAM,EAAE,GAAG,cAAc,sCAAsC,KAAK,CAAC,yBAAyB,MAAM;SACrG,CAAC;IACJ,CAAC;IAED,OAAO;QACL,cAAc,EAAE,KAAK;QACrB,cAAc;QACd,eAAe,EAAE,KAAK,CAAC,yBAAyB;KACjD,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { TokenEstimate } from '../types.js';
|
|
2
|
+
export interface EstimateOptions {
|
|
3
|
+
contextLimit?: number;
|
|
4
|
+
charsPerToken?: number;
|
|
5
|
+
startOffset?: number;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Estimate token usage from a transcript file.
|
|
9
|
+
* Uses a simple chars/4 heuristic — accurate enough for threshold comparison.
|
|
10
|
+
*/
|
|
11
|
+
export declare function estimateFromTranscript(transcriptPath: string, options?: EstimateOptions): TokenEstimate;
|
|
12
|
+
/**
|
|
13
|
+
* Quick file-size-based estimation without parsing.
|
|
14
|
+
* Much faster for threshold checks — reads only file metadata.
|
|
15
|
+
*/
|
|
16
|
+
export declare function quickEstimate(transcriptPath: string, contextLimit?: number, charsPerToken?: number): {
|
|
17
|
+
estimatedTokens: number;
|
|
18
|
+
remainingPct: number;
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=estimator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"estimator.d.ts","sourceRoot":"","sources":["../../src/transcript/estimator.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAmB,MAAM,aAAa,CAAC;AAMlE,MAAM,WAAW,eAAe;IAC9B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,cAAc,EAAE,MAAM,EACtB,OAAO,CAAC,EAAE,eAAe,GACxB,aAAa,CA2Df;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,cAAc,EAAE,MAAM,EACtB,YAAY,SAAwB,EACpC,aAAa,SAAkB,GAC9B;IAAE,eAAe,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CAiBnD"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { existsSync, statSync } from 'node:fs';
|
|
2
|
+
import { parseTranscript } from './parser.js';
|
|
3
|
+
const DEFAULT_CONTEXT_LIMIT = 200_000;
|
|
4
|
+
const CHARS_PER_TOKEN = 4;
|
|
5
|
+
/**
|
|
6
|
+
* Estimate token usage from a transcript file.
|
|
7
|
+
* Uses a simple chars/4 heuristic — accurate enough for threshold comparison.
|
|
8
|
+
*/
|
|
9
|
+
export function estimateFromTranscript(transcriptPath, options) {
|
|
10
|
+
const contextLimit = options?.contextLimit ?? DEFAULT_CONTEXT_LIMIT;
|
|
11
|
+
const charsPerToken = options?.charsPerToken ?? CHARS_PER_TOKEN;
|
|
12
|
+
if (!existsSync(transcriptPath)) {
|
|
13
|
+
return emptyEstimate(contextLimit);
|
|
14
|
+
}
|
|
15
|
+
const { entries } = parseTranscript(transcriptPath, {
|
|
16
|
+
startOffset: options?.startOffset,
|
|
17
|
+
});
|
|
18
|
+
let userChars = 0;
|
|
19
|
+
let assistantChars = 0;
|
|
20
|
+
let toolChars = 0;
|
|
21
|
+
let systemChars = 0;
|
|
22
|
+
for (const entry of entries) {
|
|
23
|
+
const text = typeof entry.content === 'string' ? entry.content : '';
|
|
24
|
+
const len = text.length;
|
|
25
|
+
switch (entry.type) {
|
|
26
|
+
case 'user':
|
|
27
|
+
userChars += len;
|
|
28
|
+
break;
|
|
29
|
+
case 'assistant':
|
|
30
|
+
assistantChars += len;
|
|
31
|
+
break;
|
|
32
|
+
case 'tool_use':
|
|
33
|
+
case 'tool_result':
|
|
34
|
+
toolChars += len;
|
|
35
|
+
break;
|
|
36
|
+
case 'system':
|
|
37
|
+
systemChars += len;
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
const totalChars = userChars + assistantChars + toolChars + systemChars;
|
|
42
|
+
const totalTokens = Math.ceil(totalChars / charsPerToken);
|
|
43
|
+
const userTokens = Math.ceil(userChars / charsPerToken);
|
|
44
|
+
const assistantTokens = Math.ceil(assistantChars / charsPerToken);
|
|
45
|
+
const toolTokens = Math.ceil(toolChars / charsPerToken);
|
|
46
|
+
const systemTokens = Math.ceil(systemChars / charsPerToken);
|
|
47
|
+
const remainingTokens = Math.max(0, contextLimit - totalTokens);
|
|
48
|
+
const remainingPct = contextLimit > 0 ? remainingTokens / contextLimit : 1;
|
|
49
|
+
return {
|
|
50
|
+
total_tokens: totalTokens,
|
|
51
|
+
message_count: entries.length,
|
|
52
|
+
user_tokens: userTokens,
|
|
53
|
+
assistant_tokens: assistantTokens,
|
|
54
|
+
tool_tokens: toolTokens,
|
|
55
|
+
system_tokens: systemTokens,
|
|
56
|
+
context_limit: contextLimit,
|
|
57
|
+
remaining_pct: Math.round(remainingPct * 100) / 100,
|
|
58
|
+
remaining_tokens: remainingTokens,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Quick file-size-based estimation without parsing.
|
|
63
|
+
* Much faster for threshold checks — reads only file metadata.
|
|
64
|
+
*/
|
|
65
|
+
export function quickEstimate(transcriptPath, contextLimit = DEFAULT_CONTEXT_LIMIT, charsPerToken = CHARS_PER_TOKEN) {
|
|
66
|
+
if (!existsSync(transcriptPath)) {
|
|
67
|
+
return { estimatedTokens: 0, remainingPct: 1 };
|
|
68
|
+
}
|
|
69
|
+
try {
|
|
70
|
+
const stat = statSync(transcriptPath);
|
|
71
|
+
// File size in bytes ≈ chars for ASCII-heavy content
|
|
72
|
+
// JSON overhead adds ~30%, so adjust
|
|
73
|
+
const estimatedContentChars = stat.size * 0.7;
|
|
74
|
+
const estimatedTokens = Math.ceil(estimatedContentChars / charsPerToken);
|
|
75
|
+
const remainingPct = Math.max(0, Math.round((1 - estimatedTokens / contextLimit) * 100) / 100);
|
|
76
|
+
return { estimatedTokens, remainingPct };
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
return { estimatedTokens: 0, remainingPct: 1 };
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
function emptyEstimate(contextLimit) {
|
|
83
|
+
return {
|
|
84
|
+
total_tokens: 0,
|
|
85
|
+
message_count: 0,
|
|
86
|
+
user_tokens: 0,
|
|
87
|
+
assistant_tokens: 0,
|
|
88
|
+
tool_tokens: 0,
|
|
89
|
+
system_tokens: 0,
|
|
90
|
+
context_limit: contextLimit,
|
|
91
|
+
remaining_pct: 1,
|
|
92
|
+
remaining_tokens: contextLimit,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=estimator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"estimator.js","sourceRoot":"","sources":["../../src/transcript/estimator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAE/C,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C,MAAM,qBAAqB,GAAG,OAAO,CAAC;AACtC,MAAM,eAAe,GAAG,CAAC,CAAC;AAQ1B;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CACpC,cAAsB,EACtB,OAAyB;IAEzB,MAAM,YAAY,GAAG,OAAO,EAAE,YAAY,IAAI,qBAAqB,CAAC;IACpE,MAAM,aAAa,GAAG,OAAO,EAAE,aAAa,IAAI,eAAe,CAAC;IAEhE,IAAI,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;QAChC,OAAO,aAAa,CAAC,YAAY,CAAC,CAAC;IACrC,CAAC;IAED,MAAM,EAAE,OAAO,EAAE,GAAG,eAAe,CAAC,cAAc,EAAE;QAClD,WAAW,EAAE,OAAO,EAAE,WAAW;KAClC,CAAC,CAAC;IAEH,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,IAAI,cAAc,GAAG,CAAC,CAAC;IACvB,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,IAAI,WAAW,GAAG,CAAC,CAAC;IAEpB,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,IAAI,GAAG,OAAO,KAAK,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;QACpE,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC;QAExB,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;YACnB,KAAK,MAAM;gBACT,SAAS,IAAI,GAAG,CAAC;gBACjB,MAAM;YACR,KAAK,WAAW;gBACd,cAAc,IAAI,GAAG,CAAC;gBACtB,MAAM;YACR,KAAK,UAAU,CAAC;YAChB,KAAK,aAAa;gBAChB,SAAS,IAAI,GAAG,CAAC;gBACjB,MAAM;YACR,KAAK,QAAQ;gBACX,WAAW,IAAI,GAAG,CAAC;gBACnB,MAAM;QACV,CAAC;IACH,CAAC;IAED,MAAM,UAAU,GAAG,SAAS,GAAG,cAAc,GAAG,SAAS,GAAG,WAAW,CAAC;IACxE,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,GAAG,aAAa,CAAC,CAAC;IAC1D,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,GAAG,aAAa,CAAC,CAAC;IACxD,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,cAAc,GAAG,aAAa,CAAC,CAAC;IAClE,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,GAAG,aAAa,CAAC,CAAC;IACxD,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,GAAG,aAAa,CAAC,CAAC;IAE5D,MAAM,eAAe,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,YAAY,GAAG,WAAW,CAAC,CAAC;IAChE,MAAM,YAAY,GAAG,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,eAAe,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;IAE3E,OAAO;QACL,YAAY,EAAE,WAAW;QACzB,aAAa,EAAE,OAAO,CAAC,MAAM;QAC7B,WAAW,EAAE,UAAU;QACvB,gBAAgB,EAAE,eAAe;QACjC,WAAW,EAAE,UAAU;QACvB,aAAa,EAAE,YAAY;QAC3B,aAAa,EAAE,YAAY;QAC3B,aAAa,EAAE,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG,GAAG,CAAC,GAAG,GAAG;QACnD,gBAAgB,EAAE,eAAe;KAClC,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAC3B,cAAsB,EACtB,YAAY,GAAG,qBAAqB,EACpC,aAAa,GAAG,eAAe;IAE/B,IAAI,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;QAChC,OAAO,EAAE,eAAe,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,CAAC;IACjD,CAAC;IAED,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,QAAQ,CAAC,cAAc,CAAC,CAAC;QACtC,qDAAqD;QACrD,qCAAqC;QACrC,MAAM,qBAAqB,GAAG,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC;QAC9C,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,qBAAqB,GAAG,aAAa,CAAC,CAAC;QACzE,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,eAAe,GAAG,YAAY,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC;QAE/F,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,CAAC;IAC3C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,eAAe,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,CAAC;IACjD,CAAC;AACH,CAAC;AAED,SAAS,aAAa,CAAC,YAAoB;IACzC,OAAO;QACL,YAAY,EAAE,CAAC;QACf,aAAa,EAAE,CAAC;QAChB,WAAW,EAAE,CAAC;QACd,gBAAgB,EAAE,CAAC;QACnB,WAAW,EAAE,CAAC;QACd,aAAa,EAAE,CAAC;QAChB,aAAa,EAAE,YAAY;QAC3B,aAAa,EAAE,CAAC;QAChB,gBAAgB,EAAE,YAAY;KAC/B,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { TranscriptEntry, ExtractionResult } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Extract structured context from transcript entries using pattern matching.
|
|
4
|
+
* Zero LLM calls — pure heuristic extraction.
|
|
5
|
+
*/
|
|
6
|
+
export declare function extractFromEntries(entries: TranscriptEntry[]): ExtractionResult;
|
|
7
|
+
//# sourceMappingURL=extractor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extractor.d.ts","sourceRoot":"","sources":["../../src/transcript/extractor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAA+D,MAAM,aAAa,CAAC;AA+BlI;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,eAAe,EAAE,GAAG,gBAAgB,CAkB/E"}
|