@tyroneross/bookmark 0.2.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.
- package/.claude-plugin/marketplace.json +29 -12
- package/.claude-plugin/plugin.json +12 -8
- package/.codex-plugin/plugin.json +31 -0
- package/.mcp.json +8 -0
- package/CLAUDE.md +82 -38
- package/LICENSE +202 -21
- package/README.md +150 -57
- package/agents/snapshot-analyst.md +1 -1
- package/commands/bookmark.md +29 -0
- package/commands/feedback.md +37 -0
- package/commands/restore.md +14 -4
- package/commands/snapshot.md +19 -7
- package/commands/status.md +1 -1
- package/dist/cli/index.js +600 -66
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/snapshot-resolution.d.ts +15 -0
- package/dist/cli/snapshot-resolution.d.ts.map +1 -0
- package/dist/cli/snapshot-resolution.js +21 -0
- package/dist/cli/snapshot-resolution.js.map +1 -0
- package/dist/config.d.ts +19 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +150 -19
- package/dist/config.js.map +1 -1
- package/dist/context/freshness.d.ts +3 -0
- package/dist/context/freshness.d.ts.map +1 -0
- package/dist/context/freshness.js +29 -0
- package/dist/context/freshness.js.map +1 -0
- package/dist/context/handoff-prompt.d.ts +12 -0
- package/dist/context/handoff-prompt.d.ts.map +1 -0
- package/dist/context/handoff-prompt.js +29 -0
- package/dist/context/handoff-prompt.js.map +1 -0
- package/dist/index.d.ts +7 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -3
- package/dist/index.js.map +1 -1
- package/dist/mcp/server.d.ts +9 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +85 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools.d.ts +97 -0
- package/dist/mcp/tools.d.ts.map +1 -0
- package/dist/mcp/tools.js +304 -0
- package/dist/mcp/tools.js.map +1 -0
- package/dist/registry.d.ts +40 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +134 -0
- package/dist/registry.js.map +1 -0
- package/dist/restore/index.d.ts +13 -1
- package/dist/restore/index.d.ts.map +1 -1
- package/dist/restore/index.js +154 -256
- package/dist/restore/index.js.map +1 -1
- package/dist/setup/auto-setup.d.ts +8 -2
- package/dist/setup/auto-setup.d.ts.map +1 -1
- package/dist/setup/auto-setup.js +281 -66
- package/dist/setup/auto-setup.js.map +1 -1
- package/dist/setup/configure-hooks.d.ts +14 -3
- package/dist/setup/configure-hooks.d.ts.map +1 -1
- package/dist/setup/configure-hooks.js +156 -24
- package/dist/setup/configure-hooks.js.map +1 -1
- package/dist/snapshot/capture.d.ts +12 -10
- package/dist/snapshot/capture.d.ts.map +1 -1
- package/dist/snapshot/capture.js +36 -48
- package/dist/snapshot/capture.js.map +1 -1
- package/dist/snapshot/compress.d.ts +3 -3
- package/dist/snapshot/compress.d.ts.map +1 -1
- package/dist/snapshot/compress.js +16 -51
- package/dist/snapshot/compress.js.map +1 -1
- package/dist/snapshot/storage.d.ts +1 -0
- package/dist/snapshot/storage.d.ts.map +1 -1
- package/dist/snapshot/storage.js +7 -6
- package/dist/snapshot/storage.js.map +1 -1
- package/dist/threshold/state.d.ts +5 -0
- package/dist/threshold/state.d.ts.map +1 -1
- package/dist/threshold/state.js +28 -2
- package/dist/threshold/state.js.map +1 -1
- package/dist/threshold/token-usage.d.ts +29 -0
- package/dist/threshold/token-usage.d.ts.map +1 -0
- package/dist/threshold/token-usage.js +128 -0
- package/dist/threshold/token-usage.js.map +1 -0
- package/dist/trails/identity.d.ts +76 -0
- package/dist/trails/identity.d.ts.map +1 -0
- package/dist/trails/identity.js +117 -0
- package/dist/trails/identity.js.map +1 -0
- package/dist/trails/reader.d.ts +1 -1
- package/dist/trails/reader.js +2 -2
- package/dist/trails/reader.js.map +1 -1
- package/dist/trails/writer.d.ts +2 -8
- package/dist/trails/writer.d.ts.map +1 -1
- package/dist/trails/writer.js +33 -191
- package/dist/trails/writer.js.map +1 -1
- package/dist/transcript/extractor.d.ts +8 -9
- package/dist/transcript/extractor.d.ts.map +1 -1
- package/dist/transcript/extractor.js +97 -360
- package/dist/transcript/extractor.js.map +1 -1
- package/dist/types.d.ts +34 -41
- package/dist/types.d.ts.map +1 -1
- package/hooks/hooks.json +12 -14
- package/package.json +13 -7
- package/scripts/install-plugin.sh +48 -0
- package/skills/context-continuity/SKILL.md +43 -24
- package/commands/activate.md +0 -20
- package/dist/transcript/estimator.d.ts +0 -20
- package/dist/transcript/estimator.d.ts.map +0 -1
- package/dist/transcript/estimator.js +0 -95
- package/dist/transcript/estimator.js.map +0 -1
|
@@ -1,45 +1,76 @@
|
|
|
1
|
-
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs';
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync, realpathSync } from 'node:fs';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
const BOOKMARK_HOOKS = {
|
|
4
|
-
|
|
4
|
+
Stop: {
|
|
5
5
|
matcher: '',
|
|
6
6
|
hooks: [{
|
|
7
7
|
type: 'command',
|
|
8
|
-
command:
|
|
9
|
-
timeout:
|
|
10
|
-
async: true,
|
|
8
|
+
command: `npx @tyroneross/bookmark stop 2>/dev/null || echo '{"decision": "approve"}'`,
|
|
9
|
+
timeout: 10000,
|
|
11
10
|
}],
|
|
12
11
|
},
|
|
13
|
-
|
|
12
|
+
PreCompact: {
|
|
14
13
|
matcher: '',
|
|
15
14
|
hooks: [{
|
|
16
15
|
type: 'command',
|
|
17
|
-
command:
|
|
18
|
-
timeout:
|
|
16
|
+
command: `npx @tyroneross/bookmark precompact 2>/dev/null || echo '{}'`,
|
|
17
|
+
timeout: 10000,
|
|
19
18
|
}],
|
|
20
19
|
},
|
|
21
|
-
|
|
20
|
+
SessionStart: {
|
|
22
21
|
matcher: '',
|
|
23
22
|
hooks: [{
|
|
24
23
|
type: 'command',
|
|
25
|
-
command:
|
|
26
|
-
timeout:
|
|
27
|
-
async: true,
|
|
24
|
+
command: `npx @tyroneross/bookmark restore 2>/dev/null || echo '{}'`,
|
|
25
|
+
timeout: 5000,
|
|
28
26
|
}],
|
|
29
27
|
},
|
|
30
|
-
|
|
28
|
+
UserPromptSubmit: {
|
|
31
29
|
matcher: '',
|
|
32
30
|
hooks: [{
|
|
33
31
|
type: 'command',
|
|
34
|
-
command:
|
|
35
|
-
timeout:
|
|
32
|
+
command: `npx @tyroneross/bookmark context-check 2>/dev/null || echo '{}'`,
|
|
33
|
+
timeout: 10000,
|
|
36
34
|
}],
|
|
37
35
|
},
|
|
38
36
|
};
|
|
39
37
|
const BOOKMARK_MARKER = '@tyroneross/bookmark';
|
|
38
|
+
const BOOKMARK_PROMPT_MARKER = '.bookmark/bookmark.context.md';
|
|
39
|
+
/**
|
|
40
|
+
* Resolve the plugin path for the settings.json plugins array.
|
|
41
|
+
* Checks for local npm install first, then global symlink.
|
|
42
|
+
*/
|
|
43
|
+
function resolvePluginPath(cwd) {
|
|
44
|
+
// Check local npm install
|
|
45
|
+
const localPlugin = join(cwd, 'node_modules', '@tyroneross', 'bookmark', '.claude-plugin');
|
|
46
|
+
if (existsSync(localPlugin)) {
|
|
47
|
+
return 'node_modules/@tyroneross/bookmark/.claude-plugin';
|
|
48
|
+
}
|
|
49
|
+
// Check global symlink
|
|
50
|
+
const home = process.env.HOME || process.env.USERPROFILE || '';
|
|
51
|
+
if (home) {
|
|
52
|
+
const globalLink = join(home, '.claude', 'plugins', 'bookmark');
|
|
53
|
+
if (existsSync(globalLink)) {
|
|
54
|
+
try {
|
|
55
|
+
const resolved = realpathSync(globalLink);
|
|
56
|
+
return join(resolved, '.claude-plugin');
|
|
57
|
+
}
|
|
58
|
+
catch { /* fall through */ }
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Check if a hook group contains a bookmark hook (command or prompt type).
|
|
65
|
+
*/
|
|
66
|
+
function isBookmarkHook(hookGroup) {
|
|
67
|
+
return hookGroup.hooks.some(hh => hh.command?.includes(BOOKMARK_MARKER) ||
|
|
68
|
+
hh.prompt?.includes(BOOKMARK_PROMPT_MARKER));
|
|
69
|
+
}
|
|
40
70
|
/**
|
|
41
|
-
* Configure hooks in the project's .claude/settings.json.
|
|
42
|
-
*
|
|
71
|
+
* Configure hooks and plugin registration in the project's .claude/settings.json.
|
|
72
|
+
* All hooks are command-type. One synchronous `context-check` hook handles
|
|
73
|
+
* interval capture and token alerts through a single state writer.
|
|
43
74
|
*/
|
|
44
75
|
export function configureHooks(cwd) {
|
|
45
76
|
const settingsDir = join(cwd, '.claude');
|
|
@@ -56,6 +87,18 @@ export function configureHooks(cwd) {
|
|
|
56
87
|
settings = {};
|
|
57
88
|
}
|
|
58
89
|
}
|
|
90
|
+
// ─── Plugin registration in settings.plugins ───
|
|
91
|
+
if (!settings.plugins) {
|
|
92
|
+
settings.plugins = [];
|
|
93
|
+
}
|
|
94
|
+
const pluginPath = resolvePluginPath(cwd);
|
|
95
|
+
if (pluginPath) {
|
|
96
|
+
const alreadyRegistered = settings.plugins.some(p => p.includes('bookmark'));
|
|
97
|
+
if (!alreadyRegistered) {
|
|
98
|
+
settings.plugins.push(pluginPath);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
// ─── Hook configuration ───
|
|
59
102
|
if (!settings.hooks) {
|
|
60
103
|
settings.hooks = {};
|
|
61
104
|
}
|
|
@@ -63,19 +106,77 @@ export function configureHooks(cwd) {
|
|
|
63
106
|
if (!settings.hooks[event]) {
|
|
64
107
|
settings.hooks[event] = [];
|
|
65
108
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
109
|
+
const existingIdx = settings.hooks[event].findIndex(isBookmarkHook);
|
|
110
|
+
if (existingIdx === -1) {
|
|
111
|
+
// No existing bookmark hook — add the new one
|
|
69
112
|
settings.hooks[event].push(hookConfig);
|
|
70
113
|
}
|
|
114
|
+
else {
|
|
115
|
+
// Replace existing bookmark hook (upgrades old prompt hooks to command hooks)
|
|
116
|
+
settings.hooks[event][existingIdx] = hookConfig;
|
|
117
|
+
}
|
|
71
118
|
}
|
|
72
119
|
writeFileSync(settingsPath, JSON.stringify(settings, null, 2), 'utf-8');
|
|
73
120
|
}
|
|
74
121
|
/**
|
|
75
|
-
*
|
|
122
|
+
* Configure hooks in the GLOBAL ~/.claude/settings.json.
|
|
123
|
+
* This makes bookmark fire in every project without per-project setup.
|
|
124
|
+
* Merges with existing hooks — never overwrites user's other hooks.
|
|
76
125
|
*/
|
|
77
|
-
export function
|
|
78
|
-
const
|
|
126
|
+
export function configureGlobalHooks() {
|
|
127
|
+
const home = process.env.HOME || process.env.USERPROFILE || '';
|
|
128
|
+
if (!home)
|
|
129
|
+
return;
|
|
130
|
+
const settingsDir = join(home, '.claude');
|
|
131
|
+
const settingsPath = join(settingsDir, 'settings.json');
|
|
132
|
+
if (!existsSync(settingsDir)) {
|
|
133
|
+
mkdirSync(settingsDir, { recursive: true });
|
|
134
|
+
}
|
|
135
|
+
let settings = {};
|
|
136
|
+
if (existsSync(settingsPath)) {
|
|
137
|
+
try {
|
|
138
|
+
settings = JSON.parse(readFileSync(settingsPath, 'utf-8'));
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
settings = {};
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
if (!settings.hooks) {
|
|
145
|
+
settings.hooks = {};
|
|
146
|
+
}
|
|
147
|
+
let changed = false;
|
|
148
|
+
for (const [event, hookConfig] of Object.entries(BOOKMARK_HOOKS)) {
|
|
149
|
+
if (!settings.hooks[event]) {
|
|
150
|
+
settings.hooks[event] = [];
|
|
151
|
+
}
|
|
152
|
+
const existingIdx = settings.hooks[event].findIndex(isBookmarkHook);
|
|
153
|
+
if (existingIdx === -1) {
|
|
154
|
+
// No existing bookmark hook — append (don't replace user's other hooks)
|
|
155
|
+
settings.hooks[event].push(hookConfig);
|
|
156
|
+
changed = true;
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
// Update existing bookmark hook in place
|
|
160
|
+
const existing = JSON.stringify(settings.hooks[event][existingIdx]);
|
|
161
|
+
const updated = JSON.stringify(hookConfig);
|
|
162
|
+
if (existing !== updated) {
|
|
163
|
+
settings.hooks[event][existingIdx] = hookConfig;
|
|
164
|
+
changed = true;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
if (changed) {
|
|
169
|
+
writeFileSync(settingsPath, JSON.stringify(settings, null, 2), 'utf-8');
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Remove bookmark hooks from the GLOBAL ~/.claude/settings.json.
|
|
174
|
+
*/
|
|
175
|
+
export function removeGlobalHooks() {
|
|
176
|
+
const home = process.env.HOME || process.env.USERPROFILE || '';
|
|
177
|
+
if (!home)
|
|
178
|
+
return;
|
|
179
|
+
const settingsPath = join(home, '.claude', 'settings.json');
|
|
79
180
|
if (!existsSync(settingsPath))
|
|
80
181
|
return;
|
|
81
182
|
try {
|
|
@@ -83,7 +184,7 @@ export function removeHooks(cwd) {
|
|
|
83
184
|
if (!settings.hooks)
|
|
84
185
|
return;
|
|
85
186
|
for (const event of Object.keys(settings.hooks)) {
|
|
86
|
-
settings.hooks[event] = settings.hooks[event].filter(h => !h
|
|
187
|
+
settings.hooks[event] = settings.hooks[event].filter(h => !isBookmarkHook(h));
|
|
87
188
|
if (settings.hooks[event].length === 0) {
|
|
88
189
|
delete settings.hooks[event];
|
|
89
190
|
}
|
|
@@ -94,4 +195,35 @@ export function removeHooks(cwd) {
|
|
|
94
195
|
// Silent
|
|
95
196
|
}
|
|
96
197
|
}
|
|
198
|
+
/**
|
|
199
|
+
* Remove bookmark hooks and plugin entry from a project's settings.json.
|
|
200
|
+
*/
|
|
201
|
+
export function removeHooks(cwd) {
|
|
202
|
+
const settingsPath = join(cwd, '.claude', 'settings.json');
|
|
203
|
+
if (!existsSync(settingsPath))
|
|
204
|
+
return;
|
|
205
|
+
try {
|
|
206
|
+
const settings = JSON.parse(readFileSync(settingsPath, 'utf-8'));
|
|
207
|
+
// Remove from plugins array
|
|
208
|
+
if (settings.plugins) {
|
|
209
|
+
settings.plugins = settings.plugins.filter(p => !p.includes('bookmark'));
|
|
210
|
+
if (settings.plugins.length === 0) {
|
|
211
|
+
delete settings.plugins;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
// Remove hooks (both command and prompt types)
|
|
215
|
+
if (settings.hooks) {
|
|
216
|
+
for (const event of Object.keys(settings.hooks)) {
|
|
217
|
+
settings.hooks[event] = settings.hooks[event].filter(h => !isBookmarkHook(h));
|
|
218
|
+
if (settings.hooks[event].length === 0) {
|
|
219
|
+
delete settings.hooks[event];
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
writeFileSync(settingsPath, JSON.stringify(settings, null, 2), 'utf-8');
|
|
224
|
+
}
|
|
225
|
+
catch {
|
|
226
|
+
// Silent
|
|
227
|
+
}
|
|
228
|
+
}
|
|
97
229
|
//# sourceMappingURL=configure-hooks.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"configure-hooks.js","sourceRoot":"","sources":["../../src/setup/configure-hooks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"configure-hooks.js","sourceRoot":"","sources":["../../src/setup/configure-hooks.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,23 +1,25 @@
|
|
|
1
1
|
import type { Snapshot, SnapshotTrigger } from '../types.js';
|
|
2
|
+
import type { ContextUsage } from '../threshold/token-usage.js';
|
|
2
3
|
export interface CaptureOptions {
|
|
3
4
|
trigger: SnapshotTrigger;
|
|
4
5
|
transcriptPath: string;
|
|
5
6
|
cwd: string;
|
|
6
7
|
sessionId?: string;
|
|
8
|
+
contextUsage?: ContextUsage;
|
|
7
9
|
}
|
|
8
10
|
/**
|
|
9
|
-
*
|
|
11
|
+
* Snapshot capture pipeline (v0.3 — file tracking only):
|
|
10
12
|
* 1. Parse transcript
|
|
11
|
-
* 2.
|
|
12
|
-
* 3.
|
|
13
|
-
* 4.
|
|
14
|
-
* 5.
|
|
15
|
-
* 6. Write LATEST.md + trail-routed files (CONTEXT.md, decisions.md, files.md)
|
|
16
|
-
* 7. Update state
|
|
13
|
+
* 2. Extract file changes + tool usage (the parts that actually work)
|
|
14
|
+
* 3. Build snapshot object
|
|
15
|
+
* 4. Store snapshot JSON + write LATEST.md + trail files
|
|
16
|
+
* 5. Update state
|
|
17
17
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
18
|
+
* Intent, decisions, and progress are NOT extracted from transcripts —
|
|
19
|
+
* regex can't do semantic extraction reliably. Instead, Claude writes
|
|
20
|
+
* bookmark.context.md directly after the token hook requests a handoff or the
|
|
21
|
+
* Stop hook blocks for one.
|
|
22
|
+
* This pipeline provides supplementary file tracking data.
|
|
21
23
|
*/
|
|
22
24
|
export declare function captureSnapshot(options: CaptureOptions): Promise<Snapshot>;
|
|
23
25
|
//# sourceMappingURL=capture.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"capture.d.ts","sourceRoot":"","sources":["../../src/snapshot/capture.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"capture.d.ts","sourceRoot":"","sources":["../../src/snapshot/capture.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAEhE,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,eAAe,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,QAAQ,CAAC,CAwDhF"}
|
package/dist/snapshot/capture.js
CHANGED
|
@@ -1,24 +1,25 @@
|
|
|
1
|
+
import { join } from 'node:path';
|
|
1
2
|
import { parseTranscript } from '../transcript/parser.js';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { storeSnapshot, writeLatestMd, loadLatestSnapshot } from './storage.js';
|
|
3
|
+
import { extractFilesAndTools } from '../transcript/extractor.js';
|
|
4
|
+
import { storeSnapshot, writeLatestMd, loadLatestSnapshot, getSnapshotsDir, generateSnapshotId } from './storage.js';
|
|
5
5
|
import { compressToMarkdown } from './compress.js';
|
|
6
6
|
import { writeTrails } from '../trails/writer.js';
|
|
7
|
-
import { loadState, saveState, updateSnapshotTime } from '../threshold/state.js';
|
|
7
|
+
import { loadState, saveState, updateSnapshotTime, incrementSnapshotCount } from '../threshold/state.js';
|
|
8
8
|
import { loadConfig, getStoragePath } from '../config.js';
|
|
9
|
+
import { appendToRegistry } from '../registry.js';
|
|
9
10
|
/**
|
|
10
|
-
*
|
|
11
|
+
* Snapshot capture pipeline (v0.3 — file tracking only):
|
|
11
12
|
* 1. Parse transcript
|
|
12
|
-
* 2.
|
|
13
|
-
* 3.
|
|
14
|
-
* 4.
|
|
15
|
-
* 5.
|
|
16
|
-
* 6. Write LATEST.md + trail-routed files (CONTEXT.md, decisions.md, files.md)
|
|
17
|
-
* 7. Update state
|
|
13
|
+
* 2. Extract file changes + tool usage (the parts that actually work)
|
|
14
|
+
* 3. Build snapshot object
|
|
15
|
+
* 4. Store snapshot JSON + write LATEST.md + trail files
|
|
16
|
+
* 5. Update state
|
|
18
17
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
18
|
+
* Intent, decisions, and progress are NOT extracted from transcripts —
|
|
19
|
+
* regex can't do semantic extraction reliably. Instead, Claude writes
|
|
20
|
+
* bookmark.context.md directly after the token hook requests a handoff or the
|
|
21
|
+
* Stop hook blocks for one.
|
|
22
|
+
* This pipeline provides supplementary file tracking data.
|
|
22
23
|
*/
|
|
23
24
|
export async function captureSnapshot(options) {
|
|
24
25
|
const config = loadConfig(options.cwd);
|
|
@@ -26,14 +27,10 @@ export async function captureSnapshot(options) {
|
|
|
26
27
|
const state = loadState(storagePath);
|
|
27
28
|
// 1. Parse transcript
|
|
28
29
|
const { entries } = parseTranscript(options.transcriptPath);
|
|
29
|
-
// 2.
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
});
|
|
34
|
-
// 3. Extract structural content via pattern matching (fast, zero external cost)
|
|
35
|
-
const extraction = extractFromEntries(entries, { projectPath: options.cwd });
|
|
36
|
-
// 4. Build snapshot
|
|
30
|
+
// 2. Extract file changes + tool usage only (working parts of extractor)
|
|
31
|
+
// Intent, decisions, and progress are NOT extracted — Claude writes the handoff.
|
|
32
|
+
const extraction = extractFilesAndTools(entries, { projectPath: options.cwd });
|
|
33
|
+
// 3. Build snapshot
|
|
37
34
|
const snapshotId = generateSnapshotId();
|
|
38
35
|
const priorSnapshot = loadLatestSnapshot(storagePath);
|
|
39
36
|
const snapshot = {
|
|
@@ -43,41 +40,32 @@ export async function captureSnapshot(options) {
|
|
|
43
40
|
project_path: options.cwd,
|
|
44
41
|
trigger: options.trigger,
|
|
45
42
|
compaction_cycle: state.compaction_count,
|
|
46
|
-
context_remaining_pct: estimate.remaining_pct,
|
|
47
|
-
token_estimate: estimate.total_tokens,
|
|
48
|
-
intent: extraction.intent ?? 'Unknown',
|
|
49
|
-
progress: extraction.progress ?? 'Unknown',
|
|
50
|
-
current_status: extraction.current_status,
|
|
51
|
-
decisions: extraction.decisions,
|
|
52
|
-
open_items: extraction.open_items,
|
|
53
|
-
unknowns: extraction.unknowns,
|
|
54
43
|
files_changed: extraction.files_changed,
|
|
55
|
-
errors_encountered: extraction.errors_encountered,
|
|
56
44
|
tools_summary: extraction.tools_summary,
|
|
57
|
-
user_sentiment: extraction.user_sentiment,
|
|
58
45
|
prior_snapshot_id: priorSnapshot?.snapshot_id,
|
|
46
|
+
context_remaining_pct: options.contextUsage?.remainingFraction,
|
|
47
|
+
context_used_pct: options.contextUsage?.usedFraction,
|
|
48
|
+
token_estimate: options.contextUsage?.usedTokens,
|
|
49
|
+
context_limit_tokens: options.contextUsage?.contextLimitTokens,
|
|
50
|
+
model: options.contextUsage?.model,
|
|
59
51
|
};
|
|
60
|
-
//
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
52
|
+
// 4. Skip empty snapshots — don't write JSON/index for 0-file non-manual captures
|
|
53
|
+
// This prevents accumulation of empty session_end snapshots
|
|
54
|
+
const hasContent = snapshot.files_changed.length > 0 ||
|
|
55
|
+
snapshot.trigger === 'manual' ||
|
|
56
|
+
snapshot.trigger === 'token_threshold';
|
|
57
|
+
if (hasContent) {
|
|
58
|
+
storeSnapshot(storagePath, snapshot);
|
|
67
59
|
const markdown = compressToMarkdown(snapshot);
|
|
68
60
|
writeLatestMd(storagePath, markdown);
|
|
69
61
|
writeTrails(storagePath, snapshot);
|
|
62
|
+
const canonicalFile = join(getSnapshotsDir(storagePath), `${snapshot.snapshot_id}.json`);
|
|
63
|
+
appendToRegistry(snapshot, canonicalFile);
|
|
70
64
|
}
|
|
71
|
-
//
|
|
65
|
+
// 6. Update state + increment snapshot counter
|
|
72
66
|
const updatedState = updateSnapshotTime(state);
|
|
73
|
-
|
|
67
|
+
const finalState = incrementSnapshotCount(updatedState);
|
|
68
|
+
saveState(storagePath, finalState);
|
|
74
69
|
return snapshot;
|
|
75
70
|
}
|
|
76
|
-
function generateSnapshotId() {
|
|
77
|
-
const now = new Date();
|
|
78
|
-
const pad = (n, len = 2) => String(n).padStart(len, '0');
|
|
79
|
-
const date = `${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}`;
|
|
80
|
-
const time = `${pad(now.getHours())}${pad(now.getMinutes())}${pad(now.getSeconds())}`;
|
|
81
|
-
return `SNAP_${date}_${time}`;
|
|
82
|
-
}
|
|
83
71
|
//# sourceMappingURL=capture.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"capture.js","sourceRoot":"","sources":["../../src/snapshot/capture.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"capture.js","sourceRoot":"","sources":["../../src/snapshot/capture.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { Snapshot } from '../types.js';
|
|
2
2
|
/**
|
|
3
|
-
* Compress a
|
|
4
|
-
*
|
|
5
|
-
* This becomes LATEST.md —
|
|
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.
|
|
6
6
|
*/
|
|
7
7
|
export declare function compressToMarkdown(snapshot: Snapshot): string;
|
|
8
8
|
//# sourceMappingURL=compress.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compress.d.ts","sourceRoot":"","sources":["../../src/snapshot/compress.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAG5C;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"compress.d.ts","sourceRoot":"","sources":["../../src/snapshot/compress.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAG5C;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,CA6C7D"}
|
|
@@ -1,50 +1,22 @@
|
|
|
1
1
|
import { basename } from 'node:path';
|
|
2
2
|
/**
|
|
3
|
-
* Compress a
|
|
4
|
-
*
|
|
5
|
-
* This becomes LATEST.md —
|
|
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.
|
|
6
6
|
*/
|
|
7
7
|
export function compressToMarkdown(snapshot) {
|
|
8
8
|
const lines = [];
|
|
9
|
-
// Header (compact)
|
|
10
9
|
const date = new Date(snapshot.timestamp).toISOString();
|
|
11
|
-
lines.push(`#
|
|
10
|
+
lines.push(`# File Changes - ${date}`);
|
|
12
11
|
lines.push('');
|
|
13
|
-
|
|
14
|
-
? ` | user: ${snapshot.user_sentiment}`
|
|
15
|
-
: '';
|
|
16
|
-
lines.push(`> ${snapshot.snapshot_id} | cycle ${snapshot.compaction_cycle} | ${snapshot.trigger} | ${Math.round(snapshot.context_remaining_pct * 100)}% ctx remaining${sentiment}`);
|
|
12
|
+
lines.push(`> ${snapshot.snapshot_id} | cycle ${snapshot.compaction_cycle} | ${snapshot.trigger}`);
|
|
17
13
|
lines.push('');
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
lines.push('
|
|
21
|
-
lines.push(snapshot.intent);
|
|
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)}`);
|
|
22
17
|
lines.push('');
|
|
23
18
|
}
|
|
24
|
-
//
|
|
25
|
-
if (snapshot.progress && snapshot.progress !== 'Unknown') {
|
|
26
|
-
lines.push('## Progress');
|
|
27
|
-
lines.push(snapshot.progress);
|
|
28
|
-
lines.push('');
|
|
29
|
-
}
|
|
30
|
-
// Key Decisions — only if present
|
|
31
|
-
if (snapshot.decisions.length > 0) {
|
|
32
|
-
lines.push('## Key Decisions');
|
|
33
|
-
for (const d of snapshot.decisions.slice(0, 4)) {
|
|
34
|
-
lines.push(`- ${truncate(d.description, 120)}`);
|
|
35
|
-
}
|
|
36
|
-
lines.push('');
|
|
37
|
-
}
|
|
38
|
-
// Open Items — remaining work
|
|
39
|
-
if (snapshot.open_items.length > 0) {
|
|
40
|
-
lines.push('## Open Items');
|
|
41
|
-
for (const item of snapshot.open_items.slice(0, 4)) {
|
|
42
|
-
const priority = item.priority === 'high' ? ' [HIGH]' : item.priority === 'medium' ? ' [MED]' : '';
|
|
43
|
-
lines.push(`- [ ] ${truncate(item.description, 120)}${priority}`);
|
|
44
|
-
}
|
|
45
|
-
lines.push('');
|
|
46
|
-
}
|
|
47
|
-
// Files Changed — use short paths with line counts
|
|
19
|
+
// Files Changed — the core value of this snapshot
|
|
48
20
|
if (snapshot.files_changed.length > 0) {
|
|
49
21
|
const totalLines = snapshot.files_changed.reduce((sum, f) => sum + (f.lines_changed ?? 0), 0);
|
|
50
22
|
lines.push(`## Files Changed (${snapshot.files_changed.length} files, ~${totalLines} lines)`);
|
|
@@ -59,14 +31,6 @@ export function compressToMarkdown(snapshot) {
|
|
|
59
31
|
}
|
|
60
32
|
lines.push('');
|
|
61
33
|
}
|
|
62
|
-
// Unknowns — only if present, very compact
|
|
63
|
-
if (snapshot.unknowns.length > 0) {
|
|
64
|
-
lines.push('## Blockers');
|
|
65
|
-
for (const u of snapshot.unknowns.slice(0, 3)) {
|
|
66
|
-
lines.push(`- ${truncate(u, 100)}`);
|
|
67
|
-
}
|
|
68
|
-
lines.push('');
|
|
69
|
-
}
|
|
70
34
|
// Tool usage — single line summary
|
|
71
35
|
if (Object.keys(snapshot.tools_summary).length > 0) {
|
|
72
36
|
const topTools = Object.entries(snapshot.tools_summary)
|
|
@@ -77,20 +41,21 @@ export function compressToMarkdown(snapshot) {
|
|
|
77
41
|
lines.push(`> Tools: ${topTools}`);
|
|
78
42
|
lines.push('');
|
|
79
43
|
}
|
|
80
|
-
lines.push('*bookmark —
|
|
44
|
+
lines.push('*bookmark — file tracking snapshot*');
|
|
81
45
|
return lines.join('\n');
|
|
82
46
|
}
|
|
83
|
-
function
|
|
84
|
-
if (
|
|
85
|
-
return
|
|
86
|
-
|
|
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);
|
|
87
53
|
}
|
|
88
54
|
/** Shorten a file path relative to project root */
|
|
89
55
|
function shortenPath(filePath, projectPath) {
|
|
90
56
|
if (projectPath && filePath.startsWith(projectPath)) {
|
|
91
57
|
return filePath.slice(projectPath.length).replace(/^\//, '');
|
|
92
58
|
}
|
|
93
|
-
// Fall back to basename for external paths
|
|
94
59
|
return basename(filePath);
|
|
95
60
|
}
|
|
96
61
|
//# sourceMappingURL=compress.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compress.js","sourceRoot":"","sources":["../../src/snapshot/compress.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAErC;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,QAAkB;IACnD,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,
|
|
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;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/snapshot/storage.ts"],"names":[],"mappings":"
|
|
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"}
|