@tyroneross/bookmark 0.1.0 → 0.3.2

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.
Files changed (109) hide show
  1. package/.claude-plugin/marketplace.json +29 -12
  2. package/.claude-plugin/plugin.json +12 -8
  3. package/.codex-plugin/plugin.json +31 -0
  4. package/.mcp.json +8 -0
  5. package/CLAUDE.md +83 -49
  6. package/LICENSE +202 -21
  7. package/README.md +150 -57
  8. package/agents/snapshot-analyst.md +1 -1
  9. package/commands/bookmark.md +29 -0
  10. package/commands/feedback.md +37 -0
  11. package/commands/restore.md +14 -4
  12. package/commands/snapshot.md +19 -7
  13. package/commands/status.md +1 -1
  14. package/dist/cli/index.js +627 -87
  15. package/dist/cli/index.js.map +1 -1
  16. package/dist/cli/snapshot-resolution.d.ts +15 -0
  17. package/dist/cli/snapshot-resolution.d.ts.map +1 -0
  18. package/dist/cli/snapshot-resolution.js +21 -0
  19. package/dist/cli/snapshot-resolution.js.map +1 -0
  20. package/dist/config.d.ts +19 -0
  21. package/dist/config.d.ts.map +1 -1
  22. package/dist/config.js +149 -23
  23. package/dist/config.js.map +1 -1
  24. package/dist/context/freshness.d.ts +3 -0
  25. package/dist/context/freshness.d.ts.map +1 -0
  26. package/dist/context/freshness.js +29 -0
  27. package/dist/context/freshness.js.map +1 -0
  28. package/dist/context/handoff-prompt.d.ts +12 -0
  29. package/dist/context/handoff-prompt.d.ts.map +1 -0
  30. package/dist/context/handoff-prompt.js +29 -0
  31. package/dist/context/handoff-prompt.js.map +1 -0
  32. package/dist/index.d.ts +7 -4
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/index.js +5 -3
  35. package/dist/index.js.map +1 -1
  36. package/dist/mcp/server.d.ts +9 -0
  37. package/dist/mcp/server.d.ts.map +1 -0
  38. package/dist/mcp/server.js +85 -0
  39. package/dist/mcp/server.js.map +1 -0
  40. package/dist/mcp/tools.d.ts +97 -0
  41. package/dist/mcp/tools.d.ts.map +1 -0
  42. package/dist/mcp/tools.js +304 -0
  43. package/dist/mcp/tools.js.map +1 -0
  44. package/dist/registry.d.ts +40 -0
  45. package/dist/registry.d.ts.map +1 -0
  46. package/dist/registry.js +134 -0
  47. package/dist/registry.js.map +1 -0
  48. package/dist/restore/index.d.ts +13 -1
  49. package/dist/restore/index.d.ts.map +1 -1
  50. package/dist/restore/index.js +163 -43
  51. package/dist/restore/index.js.map +1 -1
  52. package/dist/setup/auto-setup.d.ts +8 -2
  53. package/dist/setup/auto-setup.d.ts.map +1 -1
  54. package/dist/setup/auto-setup.js +287 -67
  55. package/dist/setup/auto-setup.js.map +1 -1
  56. package/dist/setup/configure-hooks.d.ts +14 -3
  57. package/dist/setup/configure-hooks.d.ts.map +1 -1
  58. package/dist/setup/configure-hooks.js +156 -24
  59. package/dist/setup/configure-hooks.js.map +1 -1
  60. package/dist/snapshot/capture.d.ts +13 -9
  61. package/dist/snapshot/capture.d.ts.map +1 -1
  62. package/dist/snapshot/capture.js +42 -105
  63. package/dist/snapshot/capture.js.map +1 -1
  64. package/dist/snapshot/compress.d.ts +3 -3
  65. package/dist/snapshot/compress.d.ts.map +1 -1
  66. package/dist/snapshot/compress.js +35 -67
  67. package/dist/snapshot/compress.js.map +1 -1
  68. package/dist/snapshot/storage.d.ts +7 -0
  69. package/dist/snapshot/storage.d.ts.map +1 -1
  70. package/dist/snapshot/storage.js +31 -6
  71. package/dist/snapshot/storage.js.map +1 -1
  72. package/dist/threshold/state.d.ts +5 -0
  73. package/dist/threshold/state.d.ts.map +1 -1
  74. package/dist/threshold/state.js +28 -2
  75. package/dist/threshold/state.js.map +1 -1
  76. package/dist/threshold/token-usage.d.ts +29 -0
  77. package/dist/threshold/token-usage.d.ts.map +1 -0
  78. package/dist/threshold/token-usage.js +128 -0
  79. package/dist/threshold/token-usage.js.map +1 -0
  80. package/dist/trails/identity.d.ts +76 -0
  81. package/dist/trails/identity.d.ts.map +1 -0
  82. package/dist/trails/identity.js +117 -0
  83. package/dist/trails/identity.js.map +1 -0
  84. package/dist/trails/reader.d.ts +7 -0
  85. package/dist/trails/reader.d.ts.map +1 -0
  86. package/dist/trails/reader.js +22 -0
  87. package/dist/trails/reader.js.map +1 -0
  88. package/dist/trails/writer.d.ts +9 -0
  89. package/dist/trails/writer.d.ts.map +1 -0
  90. package/dist/trails/writer.js +110 -0
  91. package/dist/trails/writer.js.map +1 -0
  92. package/dist/transcript/extractor.d.ts +17 -4
  93. package/dist/transcript/extractor.d.ts.map +1 -1
  94. package/dist/transcript/extractor.js +141 -174
  95. package/dist/transcript/extractor.js.map +1 -1
  96. package/dist/transcript/parser.d.ts.map +1 -1
  97. package/dist/transcript/parser.js +69 -7
  98. package/dist/transcript/parser.js.map +1 -1
  99. package/dist/types.d.ts +37 -38
  100. package/dist/types.d.ts.map +1 -1
  101. package/hooks/hooks.json +12 -14
  102. package/package.json +13 -10
  103. package/scripts/install-plugin.sh +48 -0
  104. package/skills/context-continuity/SKILL.md +43 -24
  105. package/commands/activate.md +0 -20
  106. package/dist/transcript/estimator.d.ts +0 -20
  107. package/dist/transcript/estimator.d.ts.map +0 -1
  108. package/dist/transcript/estimator.js +0 -95
  109. package/dist/transcript/estimator.js.map +0 -1
@@ -1,93 +1,61 @@
1
+ import { basename } from 'node:path';
1
2
  /**
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.
3
+ * Compress a snapshot into markdown now focused on file tracking data only.
4
+ * Intent/decisions/progress come from Claude-written bookmark.context.md, not this.
5
+ * This becomes LATEST.md — supplementary file change data.
5
6
  */
6
7
  export function compressToMarkdown(snapshot) {
7
8
  const lines = [];
8
- // Header
9
9
  const date = new Date(snapshot.timestamp).toISOString();
10
- lines.push(`# Session Context - Last Updated ${date}`);
10
+ lines.push(`# File Changes - ${date}`);
11
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)`);
12
+ lines.push(`> ${snapshot.snapshot_id} | cycle ${snapshot.compaction_cycle} | ${snapshot.trigger}`);
14
13
  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));
14
+ if (snapshot.context_used_pct !== undefined && snapshot.context_limit_tokens) {
15
+ const usedPct = Math.round(snapshot.context_used_pct * 100);
16
+ lines.push(`> Context: ${usedPct}% used | ${snapshot.model ?? 'unknown model'} | limit ${formatTokens(snapshot.context_limit_tokens)}`);
19
17
  lines.push('');
20
18
  }
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
19
+ // Files Changed — the core value of this snapshot
34
20
  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}`);
21
+ const totalLines = snapshot.files_changed.reduce((sum, f) => sum + (f.lines_changed ?? 0), 0);
22
+ lines.push(`## Files Changed (${snapshot.files_changed.length} files, ~${totalLines} lines)`);
23
+ for (const f of snapshot.files_changed.slice(0, 10)) {
24
+ const shortPath = shortenPath(f.path, snapshot.project_path);
25
+ const ops = f.operations.join('/');
26
+ const lc = f.lines_changed ? ` ~${f.lines_changed}L` : '';
27
+ lines.push(`- \`${shortPath}\` (${ops}${lc})`);
51
28
  }
52
- if (snapshot.open_items.length > 8) {
53
- lines.push(`- ...and ${snapshot.open_items.length - 8} more`);
29
+ if (snapshot.files_changed.length > 10) {
30
+ lines.push(`- ...+${snapshot.files_changed.length - 10} more`);
54
31
  }
55
32
  lines.push('');
56
33
  }
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)
34
+ // Tool usage — single line summary
76
35
  if (Object.keys(snapshot.tools_summary).length > 0) {
77
36
  const topTools = Object.entries(snapshot.tools_summary)
78
37
  .sort((a, b) => b[1] - a[1])
79
38
  .slice(0, 5)
80
39
  .map(([tool, count]) => `${tool}: ${count}`)
81
40
  .join(', ');
82
- lines.push(`> Tool usage: ${topTools}`);
41
+ lines.push(`> Tools: ${topTools}`);
83
42
  lines.push('');
84
43
  }
85
- lines.push('*bookmark — context snapshot*');
44
+ lines.push('*bookmark — file tracking snapshot*');
86
45
  return lines.join('\n');
87
46
  }
88
- function truncate(text, maxLen) {
89
- if (text.length <= maxLen)
90
- return text;
91
- return text.slice(0, maxLen - 3) + '...';
47
+ function formatTokens(value) {
48
+ if (value >= 1_000_000)
49
+ return `${value / 1_000_000}M`;
50
+ if (value >= 1_000)
51
+ return `${Math.round(value / 1_000)}K`;
52
+ return String(value);
53
+ }
54
+ /** Shorten a file path relative to project root */
55
+ function shortenPath(filePath, projectPath) {
56
+ if (projectPath && filePath.startsWith(projectPath)) {
57
+ return filePath.slice(projectPath.length).replace(/^\//, '');
58
+ }
59
+ return basename(filePath);
92
60
  }
93
61
  //# sourceMappingURL=compress.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"compress.js","sourceRoot":"","sources":["../../src/snapshot/compress.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"compress.js","sourceRoot":"","sources":["../../src/snapshot/compress.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import type { Snapshot, SnapshotEntry } from '../types.js';
2
+ export declare function generateSnapshotId(): string;
2
3
  export declare function getSnapshotsDir(storagePath: string): string;
3
4
  export declare function getLatestPath(storagePath: string): string;
4
5
  export declare function getIndexPath(storagePath: string): string;
@@ -10,4 +11,10 @@ export declare function listSnapshots(storagePath: string, limit?: number): Snap
10
11
  export declare function writeLatestMd(storagePath: string, content: string): void;
11
12
  export declare function readLatestMd(storagePath: string): string | null;
12
13
  export declare function getSnapshotCount(storagePath: string): number;
14
+ /**
15
+ * Walk the snapshot chain via prior_snapshot_id links.
16
+ * Returns snapshots in chronological order (oldest first).
17
+ * Caps at maxDepth to prevent runaway chains.
18
+ */
19
+ export declare function loadSnapshotChain(storagePath: string, maxDepth?: number): Snapshot[];
13
20
  //# sourceMappingURL=storage.d.ts.map
@@ -1 +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"}
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/snapshot/storage.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAiB,aAAa,EAAE,MAAM,aAAa,CAAC;AAI1E,wBAAgB,kBAAkB,IAAI,MAAM,CAQ3C;AAED,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;AA+DD,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAQ5D;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,SAAI,GAAG,QAAQ,EAAE,CAkB/E"}
@@ -1,12 +1,15 @@
1
1
  import { readFileSync, writeFileSync, existsSync, mkdirSync, readdirSync } from 'node:fs';
2
+ import { randomBytes } from 'node:crypto';
2
3
  import { join } from 'node:path';
3
4
  const INDEX_VERSION = '1.0.0';
4
- function generateSnapshotId() {
5
+ export function generateSnapshotId() {
5
6
  const now = new Date();
6
7
  const pad = (n, len = 2) => String(n).padStart(len, '0');
7
8
  const date = `${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}`;
8
9
  const time = `${pad(now.getHours())}${pad(now.getMinutes())}${pad(now.getSeconds())}`;
9
- return `SNAP_${date}_${time}`;
10
+ const milliseconds = pad(now.getMilliseconds(), 3);
11
+ const entropy = randomBytes(2).toString('hex');
12
+ return `SNAP_${date}_${time}_${milliseconds}_${entropy}`;
10
13
  }
11
14
  export function getSnapshotsDir(storagePath) {
12
15
  return join(storagePath, 'snapshots');
@@ -40,7 +43,7 @@ export function storeSnapshot(storagePath, snapshot) {
40
43
  }
41
44
  export function loadSnapshot(storagePath, snapshotId) {
42
45
  // Validate snapshot ID format to prevent path traversal
43
- if (!/^SNAP_\d{8}_\d{6}$/.test(snapshotId)) {
46
+ if (!/^SNAP_\d{8}_\d{6}(?:_\d{3}_[a-f0-9]{4})?$/.test(snapshotId)) {
44
47
  return null;
45
48
  }
46
49
  const snapshotPath = join(getSnapshotsDir(storagePath), `${snapshotId}.json`);
@@ -112,11 +115,9 @@ function updateIndex(storagePath, snapshot) {
112
115
  timestamp: snapshot.timestamp,
113
116
  trigger: snapshot.trigger,
114
117
  compaction_cycle: snapshot.compaction_cycle,
118
+ files_changed_count: snapshot.files_changed.length,
115
119
  context_remaining_pct: snapshot.context_remaining_pct,
116
120
  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
  };
121
122
  // Add to front (most recent first)
122
123
  index.snapshots.unshift(entry);
@@ -148,4 +149,28 @@ export function getSnapshotCount(storagePath) {
148
149
  return 0;
149
150
  }
150
151
  }
152
+ /**
153
+ * Walk the snapshot chain via prior_snapshot_id links.
154
+ * Returns snapshots in chronological order (oldest first).
155
+ * Caps at maxDepth to prevent runaway chains.
156
+ */
157
+ export function loadSnapshotChain(storagePath, maxDepth = 5) {
158
+ const latest = loadLatestSnapshot(storagePath);
159
+ if (!latest)
160
+ return [];
161
+ const chain = [latest];
162
+ const seen = new Set([latest.snapshot_id]);
163
+ let current = latest;
164
+ while (current.prior_snapshot_id && chain.length < maxDepth) {
165
+ if (seen.has(current.prior_snapshot_id))
166
+ break; // Prevent cycles
167
+ const prior = loadSnapshot(storagePath, current.prior_snapshot_id);
168
+ if (!prior)
169
+ break;
170
+ seen.add(prior.snapshot_id);
171
+ chain.push(prior);
172
+ current = prior;
173
+ }
174
+ return chain.reverse(); // Chronological: oldest first
175
+ }
151
176
  //# sourceMappingURL=storage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"storage.js","sourceRoot":"","sources":["../../src/snapshot/storage.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"storage.js","sourceRoot":"","sources":["../../src/snapshot/storage.ts"],"names":[],"mappings":"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"}
@@ -5,4 +5,9 @@ export declare function saveState(storagePath: string, state: BookmarkState): vo
5
5
  export declare function incrementCompaction(state: BookmarkState, thresholds: number[]): BookmarkState;
6
6
  export declare function resetForNewSession(state: BookmarkState, sessionId: string, thresholds: number[]): BookmarkState;
7
7
  export declare function updateSnapshotTime(state: BookmarkState): BookmarkState;
8
+ /**
9
+ * Increment snapshots_taken for the current session in session_history.
10
+ * Previously this was never called — snapshots_taken was always 0.
11
+ */
12
+ export declare function incrementSnapshotCount(state: BookmarkState): BookmarkState;
8
13
  //# sourceMappingURL=state.d.ts.map
@@ -1 +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"}
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,CAY7F;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,aAAa,CAgC/G;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,aAAa,GAAG,aAAa,CAMtE;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,aAAa,GAAG,aAAa,CAW1E"}
@@ -10,7 +10,7 @@ function defaultState() {
10
10
  current_threshold: 0.20,
11
11
  last_snapshot_time: 0,
12
12
  last_event_time: 0,
13
- snapshot_interval_minutes: 20,
13
+ snapshot_interval_minutes: 5,
14
14
  session_history: [],
15
15
  };
16
16
  }
@@ -46,6 +46,10 @@ export function incrementCompaction(state, thresholds) {
46
46
  ...state,
47
47
  compaction_count: newCount,
48
48
  current_threshold: thresholds[thresholdIndex],
49
+ // The first prompt after compaction can still see the final pre-compaction
50
+ // usage record. Keep handled thresholds until a lower usage record proves
51
+ // the new context cycle is active.
52
+ token_thresholds_triggered: state.token_thresholds_triggered,
49
53
  };
50
54
  }
51
55
  export function resetForNewSession(state, sessionId, thresholds) {
@@ -57,7 +61,7 @@ export function resetForNewSession(state, sessionId, thresholds) {
57
61
  started: state.session_history.find(s => s.session_id === state.session_id)?.started ?? state.last_event_time,
58
62
  ended: Date.now(),
59
63
  compaction_count: state.compaction_count,
60
- snapshots_taken: 0, // Updated elsewhere
64
+ snapshots_taken: 0, // Incremented by incrementSnapshotCount on each capture
61
65
  };
62
66
  history.unshift(currentEntry);
63
67
  if (history.length > MAX_SESSION_HISTORY) {
@@ -71,6 +75,13 @@ export function resetForNewSession(state, sessionId, thresholds) {
71
75
  current_threshold: thresholds[0],
72
76
  last_event_time: Date.now(),
73
77
  session_history: history,
78
+ token_thresholds_triggered: [],
79
+ latest_model: undefined,
80
+ latest_context_tokens: undefined,
81
+ latest_context_limit_tokens: undefined,
82
+ latest_context_used_pct: undefined,
83
+ latest_context_observed_at: undefined,
84
+ unknown_context_limit_notified_model: undefined,
74
85
  };
75
86
  }
76
87
  export function updateSnapshotTime(state) {
@@ -80,4 +91,19 @@ export function updateSnapshotTime(state) {
80
91
  last_event_time: Date.now(),
81
92
  };
82
93
  }
94
+ /**
95
+ * Increment snapshots_taken for the current session in session_history.
96
+ * Previously this was never called — snapshots_taken was always 0.
97
+ */
98
+ export function incrementSnapshotCount(state) {
99
+ if (!state.session_id)
100
+ return state;
101
+ const history = state.session_history.map(entry => {
102
+ if (entry.session_id === state.session_id) {
103
+ return { ...entry, snapshots_taken: entry.snapshots_taken + 1 };
104
+ }
105
+ return entry;
106
+ });
107
+ return { ...state, session_history: history };
108
+ }
83
109
  //# sourceMappingURL=state.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/threshold/state.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/threshold/state.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ export interface ContextUsage {
2
+ status: 'measured';
3
+ model: string;
4
+ usedTokens: number;
5
+ contextLimitTokens: number;
6
+ usedFraction: number;
7
+ remainingFraction: number;
8
+ source: 'transcript_usage';
9
+ }
10
+ export interface UnknownContextLimitUsage {
11
+ status: 'unknown_context_limit';
12
+ model: string;
13
+ usedTokens: number;
14
+ source: 'transcript_usage';
15
+ }
16
+ export type ContextUsageObservation = ContextUsage | UnknownContextLimitUsage;
17
+ /**
18
+ * Resolve the context limit for models observed in Claude Code transcripts.
19
+ * An explicit override wins so users can handle provider/model changes without
20
+ * waiting for a Bookmark release. Unknown models return null so Bookmark can
21
+ * ask for a verified limit instead of guessing.
22
+ */
23
+ export declare function resolveContextLimit(model: string, override?: number): number | null;
24
+ /** Read only the transcript tail and return the latest assistant usage record. */
25
+ export declare function readLatestContextUsage(transcriptPath: string, contextLimitOverride?: number, pendingPrompt?: string): ContextUsageObservation | null;
26
+ export declare function newlyCrossedThresholds(usedFraction: number, configuredThresholds: number[], alreadyTriggered?: number[]): number[];
27
+ /** Re-arm alerts only after a lower usage record proves a new context cycle. */
28
+ export declare function handledThresholdsForUsage(usedFraction: number, configuredThresholds: number[], alreadyTriggered?: number[]): number[];
29
+ //# sourceMappingURL=token-usage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-usage.d.ts","sourceRoot":"","sources":["../../src/threshold/token-usage.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,UAAU,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,MAAM,EAAE,kBAAkB,CAAC;CAC5B;AAED,MAAM,WAAW,wBAAwB;IACvC,MAAM,EAAE,uBAAuB,CAAC;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,kBAAkB,CAAC;CAC5B;AAED,MAAM,MAAM,uBAAuB,GAAG,YAAY,GAAG,wBAAwB,CAAC;AAE9E;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAkBnF;AAED,kFAAkF;AAClF,wBAAgB,sBAAsB,CACpC,cAAc,EAAE,MAAM,EACtB,oBAAoB,CAAC,EAAE,MAAM,EAC7B,aAAa,SAAK,GACjB,uBAAuB,GAAG,IAAI,CA0EhC;AAED,wBAAgB,sBAAsB,CACpC,YAAY,EAAE,MAAM,EACpB,oBAAoB,EAAE,MAAM,EAAE,EAC9B,gBAAgB,GAAE,MAAM,EAAO,GAC9B,MAAM,EAAE,CAMV;AAED,gFAAgF;AAChF,wBAAgB,yBAAyB,CACvC,YAAY,EAAE,MAAM,EACpB,oBAAoB,EAAE,MAAM,EAAE,EAC9B,gBAAgB,GAAE,MAAM,EAAO,GAC9B,MAAM,EAAE,CAGV"}
@@ -0,0 +1,128 @@
1
+ import { closeSync, existsSync, fstatSync, openSync, readSync } from 'node:fs';
2
+ const MAX_TAIL_BYTES = 4 * 1024 * 1024;
3
+ /**
4
+ * Resolve the context limit for models observed in Claude Code transcripts.
5
+ * An explicit override wins so users can handle provider/model changes without
6
+ * waiting for a Bookmark release. Unknown models return null so Bookmark can
7
+ * ask for a verified limit instead of guessing.
8
+ */
9
+ export function resolveContextLimit(model, override) {
10
+ if (override && Number.isFinite(override) && override > 0)
11
+ return override;
12
+ const normalized = normalizeModelId(model);
13
+ const hasOneMillionContext = [
14
+ /^claude-(?:opus|sonnet|fable|mythos)-5(?:-|$)/,
15
+ /^claude-opus-4-(?:6|7|8)(?:-|$)/,
16
+ /^claude-sonnet-4-6(?:-|$)/,
17
+ /^claude-mythos-preview(?:-|$)/,
18
+ ].some(pattern => pattern.test(normalized));
19
+ if (hasOneMillionContext)
20
+ return 1_000_000;
21
+ const hasTwoHundredThousandContext = [
22
+ /^claude-(?:opus|sonnet|haiku)-4-5(?:-|$)/,
23
+ ].some(pattern => pattern.test(normalized));
24
+ return hasTwoHundredThousandContext ? 200_000 : null;
25
+ }
26
+ /** Read only the transcript tail and return the latest assistant usage record. */
27
+ export function readLatestContextUsage(transcriptPath, contextLimitOverride, pendingPrompt = '') {
28
+ if (!existsSync(transcriptPath))
29
+ return null;
30
+ let fd;
31
+ try {
32
+ fd = openSync(transcriptPath, 'r');
33
+ const size = fstatSync(fd).size;
34
+ if (size === 0)
35
+ return null;
36
+ const bytesToRead = Math.min(size, MAX_TAIL_BYTES);
37
+ const start = size - bytesToRead;
38
+ const buffer = Buffer.alloc(bytesToRead);
39
+ readSync(fd, buffer, 0, bytesToRead, start);
40
+ let text = buffer.toString('utf8');
41
+ if (start > 0) {
42
+ const firstNewline = text.indexOf('\n');
43
+ text = firstNewline >= 0 ? text.slice(firstNewline + 1) : '';
44
+ }
45
+ const lines = text.split('\n');
46
+ for (let index = lines.length - 1; index >= 0; index -= 1) {
47
+ const line = lines[index].trim();
48
+ if (!line)
49
+ continue;
50
+ try {
51
+ const record = JSON.parse(line);
52
+ if (typeof record.type === 'string' && record.type !== 'assistant')
53
+ continue;
54
+ const message = isRecord(record.message) ? record.message : record;
55
+ const usage = isRecord(message.usage) ? message.usage : null;
56
+ const model = typeof message.model === 'string' ? message.model : null;
57
+ if (!usage || !model || model === '<synthetic>')
58
+ continue;
59
+ const inputTokens = tokenCount(usage.input_tokens);
60
+ const cacheCreationTokens = tokenCount(usage.cache_creation_input_tokens);
61
+ const cacheReadTokens = tokenCount(usage.cache_read_input_tokens);
62
+ const outputTokens = tokenCount(usage.output_tokens);
63
+ const promptEstimate = pendingPrompt
64
+ ? Math.ceil(Buffer.byteLength(pendingPrompt, 'utf8') / 4)
65
+ : 0;
66
+ const usedTokens = inputTokens + cacheCreationTokens + cacheReadTokens + outputTokens + promptEstimate;
67
+ if (usedTokens <= 0)
68
+ continue;
69
+ const contextLimitTokens = resolveContextLimit(model, contextLimitOverride);
70
+ if (contextLimitTokens === null) {
71
+ return {
72
+ status: 'unknown_context_limit',
73
+ model,
74
+ usedTokens,
75
+ source: 'transcript_usage',
76
+ };
77
+ }
78
+ const usedFraction = Math.min(usedTokens / contextLimitTokens, 1);
79
+ return {
80
+ status: 'measured',
81
+ model,
82
+ usedTokens,
83
+ contextLimitTokens,
84
+ usedFraction,
85
+ remainingFraction: Math.max(0, 1 - usedFraction),
86
+ source: 'transcript_usage',
87
+ };
88
+ }
89
+ catch {
90
+ // Skip malformed or partial JSONL lines.
91
+ }
92
+ }
93
+ }
94
+ catch {
95
+ return null;
96
+ }
97
+ finally {
98
+ if (fd !== undefined)
99
+ closeSync(fd);
100
+ }
101
+ return null;
102
+ }
103
+ export function newlyCrossedThresholds(usedFraction, configuredThresholds, alreadyTriggered = []) {
104
+ const handled = new Set(alreadyTriggered.map(value => Number(value.toFixed(4))));
105
+ return [...configuredThresholds]
106
+ .filter(value => Number.isFinite(value) && value > 0 && value < 1)
107
+ .sort((a, b) => a - b)
108
+ .filter(value => usedFraction >= value && !handled.has(Number(value.toFixed(4))));
109
+ }
110
+ /** Re-arm alerts only after a lower usage record proves a new context cycle. */
111
+ export function handledThresholdsForUsage(usedFraction, configuredThresholds, alreadyTriggered = []) {
112
+ const lowestThreshold = Math.min(...configuredThresholds);
113
+ return usedFraction < lowestThreshold ? [] : alreadyTriggered;
114
+ }
115
+ function tokenCount(value) {
116
+ return typeof value === 'number' && Number.isFinite(value) && value > 0 ? value : 0;
117
+ }
118
+ function normalizeModelId(model) {
119
+ return model
120
+ .toLowerCase()
121
+ .replace(/^anthropic\./, '')
122
+ .replace(/-v\d+:\d+$/, '')
123
+ .replace(/@(\d{8})$/, '-$1');
124
+ }
125
+ function isRecord(value) {
126
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
127
+ }
128
+ //# sourceMappingURL=token-usage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-usage.js","sourceRoot":"","sources":["../../src/threshold/token-usage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * BOOKMARK_IDENTITY block parser + validator.
3
+ *
4
+ * The identity block is an HTML comment at the top of bookmark.context.md
5
+ * that declares which project/repo/branch the summary belongs to. It makes
6
+ * cross-session restoration unambiguous — you can always verify the
7
+ * bookmark you're restoring from matches the CWD you're restoring into.
8
+ *
9
+ * Example:
10
+ * <!-- BOOKMARK_IDENTITY
11
+ * scope: repo
12
+ * project: travel-planner
13
+ * repo_path: /Users/me/Desktop/git-folder/Travel Planner
14
+ * branch: feature/summer-camps
15
+ * head: 4988383
16
+ * written: 2026-04-11
17
+ * -->
18
+ *
19
+ * Two scopes are supported:
20
+ * - `repo` — bookmark belongs to a specific git repo (or directory)
21
+ * - `home` — bookmark is a POINTER, no active context itself; delegates
22
+ * via `points_to_canonical` to a repo-scoped bookmark
23
+ */
24
+ export type BookmarkScope = 'repo' | 'home';
25
+ export interface BookmarkIdentity {
26
+ scope: BookmarkScope;
27
+ project?: string;
28
+ repo_path?: string;
29
+ repo_name?: string;
30
+ branch?: string;
31
+ head?: string;
32
+ base?: string;
33
+ written?: string;
34
+ written_by?: string;
35
+ points_to_project?: string;
36
+ points_to_repo?: string;
37
+ points_to_canonical?: string;
38
+ /** All raw key:value pairs, for forward-compat keys we don't model */
39
+ raw: Record<string, string>;
40
+ }
41
+ export interface IdentityParseResult {
42
+ identity: BookmarkIdentity | null;
43
+ /** Content with the identity block stripped, ready to present */
44
+ bodyWithoutIdentity: string;
45
+ }
46
+ /**
47
+ * Parse a bookmark.context.md file's content and extract the identity block.
48
+ * Returns `identity: null` if no block is present — callers should treat that
49
+ * as a legacy/untagged file and fall back to current behavior.
50
+ */
51
+ export declare function parseIdentity(content: string): IdentityParseResult;
52
+ /**
53
+ * Validate a repo-scoped identity against the storage path that was loaded.
54
+ *
55
+ * Returns a warning string if the identity's `repo_path` disagrees with the
56
+ * working directory, suggesting the bookmark file was moved or the CWD is
57
+ * not the repo it describes. Returns null when they match or when we can't
58
+ * determine (missing field).
59
+ */
60
+ export declare function validateRepoIdentity(identity: BookmarkIdentity, cwd: string): string | null;
61
+ /**
62
+ * Follow a home-scope pointer to its canonical file.
63
+ *
64
+ * If the identity is home-scoped and has `points_to_canonical`, return the
65
+ * content of that file (plus its own parsed identity). Returns null if the
66
+ * pointer target doesn't exist or isn't readable — caller should fall back
67
+ * to presenting the pointer body itself.
68
+ */
69
+ export interface PointerTarget {
70
+ canonical_path: string;
71
+ content: string;
72
+ identity: BookmarkIdentity | null;
73
+ staleness_hours: number | null;
74
+ }
75
+ export declare function followPointer(identity: BookmarkIdentity): PointerTarget | null;
76
+ //# sourceMappingURL=identity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../../src/trails/identity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAKH,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,MAAM,CAAC;AAE5C,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,aAAa,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,sEAAsE;IACtE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC7B;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAClC,iEAAiE;IACjE,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAID;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,mBAAmB,CAwClE;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,gBAAgB,EAC1B,GAAG,EAAE,MAAM,GACV,MAAM,GAAG,IAAI,CAiBf;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,aAAa;IAC5B,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAClC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,gBAAgB,GAAG,aAAa,GAAG,IAAI,CAqB9E"}