@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
@@ -0,0 +1,134 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
2
+ import { basename, dirname, join } from 'node:path';
3
+ import { homedir } from 'node:os';
4
+ const REGISTRY_VERSION = '1.0.0';
5
+ const MAX_ENTRIES = 500;
6
+ /**
7
+ * Resolve a human-readable project name from a directory path.
8
+ *
9
+ * Resolution order:
10
+ * 1. package.json "name" field in cwd
11
+ * 2. basename of git repo root (walk up until .git is found)
12
+ * 3. basename of cwd — unless it's the home directory
13
+ * 4. Fallback: basename(cwd) regardless
14
+ */
15
+ export function resolveProjectName(cwd) {
16
+ const home = homedir();
17
+ // 1. package.json name
18
+ const pkgPath = join(cwd, 'package.json');
19
+ if (existsSync(pkgPath)) {
20
+ try {
21
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
22
+ if (pkg.name && pkg.name.trim()) {
23
+ // Strip scoped package prefix (@scope/name → name)
24
+ return pkg.name.replace(/^@[^/]+\//, '').trim();
25
+ }
26
+ }
27
+ catch {
28
+ // Fall through
29
+ }
30
+ }
31
+ // 2. Walk up looking for .git directory
32
+ let dir = cwd;
33
+ const root = dirname(home); // Stop before going above home's parent
34
+ while (dir && dir !== root && dir !== dirname(dir)) {
35
+ if (existsSync(join(dir, '.git'))) {
36
+ return basename(dir);
37
+ }
38
+ dir = dirname(dir);
39
+ }
40
+ // 3. Avoid returning home dir basename as the name
41
+ const cwdBase = basename(cwd);
42
+ if (cwd === home || cwdBase === basename(home)) {
43
+ return 'home';
44
+ }
45
+ return cwdBase;
46
+ }
47
+ export function getRegistryPath() {
48
+ return join(homedir(), '.bookmark', 'registry.json');
49
+ }
50
+ function ensureRegistryDir() {
51
+ const dir = join(homedir(), '.bookmark');
52
+ if (!existsSync(dir))
53
+ mkdirSync(dir, { recursive: true });
54
+ }
55
+ export function loadRegistry() {
56
+ const path = getRegistryPath();
57
+ if (!existsSync(path)) {
58
+ return { version: REGISTRY_VERSION, last_updated: 0, snapshots: [] };
59
+ }
60
+ try {
61
+ const parsed = JSON.parse(readFileSync(path, 'utf-8'));
62
+ if (!parsed.snapshots)
63
+ parsed.snapshots = [];
64
+ return parsed;
65
+ }
66
+ catch {
67
+ return { version: REGISTRY_VERSION, last_updated: 0, snapshots: [] };
68
+ }
69
+ }
70
+ function saveRegistry(registry) {
71
+ ensureRegistryDir();
72
+ registry.last_updated = Date.now();
73
+ writeFileSync(getRegistryPath(), JSON.stringify(registry, null, 2), 'utf-8');
74
+ }
75
+ export function appendToRegistry(snapshot, canonicalFile) {
76
+ try {
77
+ const registry = loadRegistry();
78
+ const entry = {
79
+ id: snapshot.snapshot_id,
80
+ timestamp: snapshot.timestamp,
81
+ trigger: snapshot.trigger,
82
+ project_path: snapshot.project_path,
83
+ project_name: resolveProjectName(snapshot.project_path),
84
+ canonical_file: canonicalFile,
85
+ files_changed_count: snapshot.files_changed.length,
86
+ };
87
+ // Dedupe by id, newest wins
88
+ registry.snapshots = [entry, ...registry.snapshots.filter(e => e.id !== entry.id)];
89
+ if (registry.snapshots.length > MAX_ENTRIES) {
90
+ registry.snapshots.length = MAX_ENTRIES;
91
+ }
92
+ registry.last_project = {
93
+ path: snapshot.project_path,
94
+ name: entry.project_name,
95
+ last_activity_at: snapshot.timestamp,
96
+ };
97
+ saveRegistry(registry);
98
+ }
99
+ catch {
100
+ // Never break capture for registry bookkeeping
101
+ }
102
+ }
103
+ export function touchLastProject(projectPath) {
104
+ try {
105
+ const registry = loadRegistry();
106
+ registry.last_project = {
107
+ path: projectPath,
108
+ name: resolveProjectName(projectPath),
109
+ last_activity_at: Date.now(),
110
+ };
111
+ saveRegistry(registry);
112
+ }
113
+ catch {
114
+ // Silent — never break restore for bookkeeping
115
+ }
116
+ }
117
+ export function findById(id) {
118
+ const registry = loadRegistry();
119
+ return registry.snapshots.find(e => e.id === id) ?? null;
120
+ }
121
+ export function getLastProject() {
122
+ return loadRegistry().last_project ?? null;
123
+ }
124
+ /** Prune entries whose canonical_file is missing. Lazy cleanup on read paths. */
125
+ export function pruneStale() {
126
+ const registry = loadRegistry();
127
+ const live = registry.snapshots.filter(e => existsSync(e.canonical_file));
128
+ if (live.length !== registry.snapshots.length) {
129
+ registry.snapshots = live;
130
+ saveRegistry(registry);
131
+ }
132
+ return registry;
133
+ }
134
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"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"}
@@ -7,7 +7,19 @@ export interface RestoreOptions {
7
7
  }
8
8
  /**
9
9
  * Generate restoration context for a SessionStart hook.
10
- * Returns a HookOutput with systemMessage containing the LATEST.md content.
10
+ *
11
+ * v0.4 adds:
12
+ * 1. BOOKMARK_IDENTITY parsing + repo_path validation
13
+ * 2. Home-scope pointer delegation to a canonical repo bookmark
14
+ * 3. Hard staleness block at 72h (instead of soft warning only)
15
+ *
16
+ * Cascade:
17
+ * 1. bookmark.context.md — if present and useful
18
+ * 1a. If identity scope=home + points_to_canonical, follow the pointer
19
+ * 1b. If identity scope=repo and path mismatch, prefix a warning
20
+ * 1c. If age >= STALENESS_HARD_BLOCK_HOURS, return staleness block
21
+ * 2. LATEST.md — file tracking fallback
22
+ * 3. Empty
11
23
  */
12
24
  export declare function restoreContext(options: RestoreOptions): HookOutput;
13
25
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/restore/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAiB,MAAM,aAAa,CAAC;AAE7D,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,EAAE,SAAS,GAAG,QAAQ,GAAG,SAAS,GAAG,OAAO,CAAC;IACpD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,gBAAgB,GAAG,MAAM,GAAG,UAAU,CAAC;CACjD;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,cAAc,GAAG,UAAU,CAoDlE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/restore/index.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,UAAU,EAAiB,MAAM,aAAa,CAAC;AAE7D,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,EAAE,SAAS,GAAG,QAAQ,GAAG,SAAS,GAAG,OAAO,CAAC;IACpD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,gBAAgB,GAAG,MAAM,GAAG,UAAU,CAAC;CACjD;AAWD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,cAAc,GAAG,UAAU,CAqFlE"}
@@ -1,67 +1,190 @@
1
- import { existsSync } from 'node:fs';
2
- import { readLatestMd, loadLatestSnapshot, getSnapshotCount } from '../snapshot/storage.js';
1
+ import { existsSync, statSync, unlinkSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { readLatestMd, getSnapshotCount } from '../snapshot/storage.js';
4
+ import { readContextMd } from '../trails/reader.js';
5
+ import { parseIdentity, validateRepoIdentity, followPointer, } from '../trails/identity.js';
3
6
  import { loadState, saveState, resetForNewSession, incrementCompaction } from '../threshold/state.js';
4
7
  import { loadConfig, getStoragePath } from '../config.js';
8
+ import { touchLastProject } from '../registry.js';
9
+ /**
10
+ * Hours after which a bookmark is considered too stale to auto-restore.
11
+ * Below this threshold: restore with a soft warning.
12
+ * At or above: hard-block — return an empty context with guidance instead
13
+ * of risking a confident wrong start from stale content.
14
+ */
15
+ const STALENESS_HARD_BLOCK_HOURS = 72;
16
+ const STALENESS_SOFT_WARN_HOURS = 24;
5
17
  /**
6
18
  * Generate restoration context for a SessionStart hook.
7
- * Returns a HookOutput with systemMessage containing the LATEST.md content.
19
+ *
20
+ * v0.4 adds:
21
+ * 1. BOOKMARK_IDENTITY parsing + repo_path validation
22
+ * 2. Home-scope pointer delegation to a canonical repo bookmark
23
+ * 3. Hard staleness block at 72h (instead of soft warning only)
24
+ *
25
+ * Cascade:
26
+ * 1. bookmark.context.md — if present and useful
27
+ * 1a. If identity scope=home + points_to_canonical, follow the pointer
28
+ * 1b. If identity scope=repo and path mismatch, prefix a warning
29
+ * 1c. If age >= STALENESS_HARD_BLOCK_HOURS, return staleness block
30
+ * 2. LATEST.md — file tracking fallback
31
+ * 3. Empty
8
32
  */
9
33
  export function restoreContext(options) {
10
34
  const config = loadConfig(options.cwd);
11
35
  const storagePath = getStoragePath(options.cwd, config);
12
36
  const state = loadState(storagePath);
13
- // Handle session state transitions
14
37
  handleSessionTransition(storagePath, state, options, config.thresholds);
15
- // Check if restoration is needed
16
- if (!config.restoreOnSessionStart) {
17
- return {};
38
+ const stopRequestedPath = join(storagePath, '.stop-requested');
39
+ if (existsSync(stopRequestedPath)) {
40
+ try {
41
+ unlinkSync(stopRequestedPath);
42
+ }
43
+ catch { /* ignore */ }
18
44
  }
19
- // On resume, context is likely intact — skip restoration
20
- if (options.source === 'resume') {
45
+ if (!config.restoreOnSessionStart)
21
46
  return {};
47
+ if (options.source === 'resume')
48
+ return {};
49
+ // Primary: bookmark.context.md with identity-aware handling
50
+ const rawContextMd = readContextMd(storagePath);
51
+ if (rawContextMd && isContextMdUseful(rawContextMd)) {
52
+ const contextPath = join(storagePath, 'bookmark.context.md');
53
+ const { identity, bodyWithoutIdentity } = parseIdentity(rawContextMd);
54
+ // 1a. Home-scope pointer? Follow it to the canonical repo bookmark.
55
+ if (identity?.scope === 'home') {
56
+ const target = followPointer(identity);
57
+ if (target) {
58
+ const targetAge = target.staleness_hours ?? 0;
59
+ if (targetAge >= STALENESS_HARD_BLOCK_HOURS) {
60
+ trackRestore(storagePath, 0);
61
+ return { systemMessage: buildHardStalenessMessage(target.canonical_path, targetAge) };
62
+ }
63
+ // Strip identity block from target content for cleaner display
64
+ const { bodyWithoutIdentity: targetBody } = parseIdentity(target.content);
65
+ const header = buildPointerFollowHeader(identity, target.canonical_path, targetAge);
66
+ const message = `${header}\n\n${targetBody}`;
67
+ trackRestore(storagePath, message.length);
68
+ if (identity.points_to_canonical) {
69
+ touchLastProject(derivProjectFromCanonical(identity.points_to_canonical));
70
+ }
71
+ return { systemMessage: message };
72
+ }
73
+ // Pointer target missing — fall through to present the pointer body itself
74
+ }
75
+ // 1c. Hard staleness block
76
+ const ageHours = getAgeHours(contextPath);
77
+ if (ageHours !== null && ageHours >= STALENESS_HARD_BLOCK_HOURS) {
78
+ trackRestore(storagePath, 0);
79
+ return { systemMessage: buildHardStalenessMessage(contextPath, ageHours) };
80
+ }
81
+ // 1b. Path-mismatch warning for repo-scoped identities
82
+ const mismatchWarning = identity ? validateRepoIdentity(identity, options.cwd) : null;
83
+ // Soft staleness warning
84
+ const softWarning = ageHours !== null && ageHours >= STALENESS_SOFT_WARN_HOURS
85
+ ? `[Note: This bookmark context is ${ageHours}h old and may be outdated.]`
86
+ : null;
87
+ const prefixes = [mismatchWarning, softWarning].filter(Boolean).join('\n\n');
88
+ const message = prefixes ? `${prefixes}\n\n${bodyWithoutIdentity}` : bodyWithoutIdentity;
89
+ trackRestore(storagePath, message.length);
90
+ touchLastProject(options.cwd);
91
+ return { systemMessage: message };
22
92
  }
23
- // Check for existing snapshots
24
- const snapshotCount = getSnapshotCount(storagePath);
25
- if (snapshotCount === 0) {
26
- // First run — tell Claude that bookmark is active
27
- return {
28
- systemMessage: '[Bookmark: Active — no snapshots yet. Snapshots will be captured automatically ' +
29
- 'before compaction, on 20-minute intervals, and at session end.]\n\n' +
30
- 'Briefly let the user know that Bookmark is active and will start capturing context snapshots automatically.',
31
- };
93
+ if (rawContextMd) {
94
+ trackBoilerplateCaught(storagePath);
32
95
  }
33
- // Read LATEST.md
96
+ // Fallback: LATEST.md
97
+ const snapshotCount = getSnapshotCount(storagePath);
34
98
  const latestMd = readLatestMd(storagePath);
35
- if (!latestMd) {
36
- return {};
99
+ if (latestMd) {
100
+ const message = buildFallbackRestoration(latestMd, snapshotCount);
101
+ trackRestore(storagePath, message.length);
102
+ touchLastProject(options.cwd);
103
+ return { systemMessage: message };
104
+ }
105
+ // No local bookmark and no LATEST.md — stay silent rather than inject
106
+ // another repo's context. The home-scope pointer at ~/.bookmark/bookmark.context.md
107
+ // is the supported way to redirect from an empty CWD to a canonical project.
108
+ return {};
109
+ }
110
+ /** Derive the project path from a canonical bookmark.context.md path. */
111
+ function derivProjectFromCanonical(canonicalPath) {
112
+ // .../<project>/.bookmark/bookmark.context.md → <project>
113
+ const marker = `/.bookmark/`;
114
+ const idx = canonicalPath.lastIndexOf(marker);
115
+ return idx > 0 ? canonicalPath.slice(0, idx) : canonicalPath;
116
+ }
117
+ /** Record a successful restore — chars injected / 4 ≈ tokens */
118
+ function trackRestore(storagePath, charCount) {
119
+ try {
120
+ const state = loadState(storagePath);
121
+ state.restores_performed = (state.restores_performed ?? 0) + 1;
122
+ state.tokens_injected = (state.tokens_injected ?? 0) + Math.round(charCount / 4);
123
+ saveState(storagePath, state);
124
+ }
125
+ catch { /* never break restore for tracking */ }
126
+ }
127
+ function trackBoilerplateCaught(storagePath) {
128
+ try {
129
+ const state = loadState(storagePath);
130
+ state.boilerplate_caught = (state.boilerplate_caught ?? 0) + 1;
131
+ saveState(storagePath, state);
37
132
  }
38
- if (options.format === 'json') {
39
- const snapshot = loadLatestSnapshot(storagePath);
40
- return {
41
- systemMessage: JSON.stringify(snapshot, null, 2),
42
- };
133
+ catch { /* never break restore for tracking */ }
134
+ }
135
+ function isContextMdUseful(content) {
136
+ if (content.length < 200)
137
+ return false;
138
+ if (content.startsWith('[Bookmark Context') && !content.includes('## '))
139
+ return false;
140
+ const markers = ['## ', '**Task', '**Status', '**Progress', 'done', 'remaining', '- '];
141
+ return markers.some(m => content.includes(m));
142
+ }
143
+ function getAgeHours(path) {
144
+ try {
145
+ const mtime = statSync(path).mtimeMs;
146
+ return Math.round((Date.now() - mtime) / (1000 * 60 * 60));
43
147
  }
44
- if (options.format === 'markdown') {
45
- return {
46
- systemMessage: latestMd,
47
- };
148
+ catch {
149
+ return null;
48
150
  }
49
- // Default: system_message format
50
- const systemMessage = buildRestorationMessage(latestMd, snapshotCount);
51
- return { systemMessage };
52
151
  }
53
- function buildRestorationMessage(latestMd, snapshotCount) {
152
+ function buildHardStalenessMessage(path, ageHours) {
153
+ return [
154
+ `[Bookmark: auto-restore BLOCKED — source is ${ageHours}h stale (threshold ${STALENESS_HARD_BLOCK_HOURS}h).]`,
155
+ '',
156
+ `The bookmark file at ${path} is too old to treat as current context.`,
157
+ 'Stale auto-restore creates confident wrong starts — worse than no restore at all.',
158
+ '',
159
+ 'To proceed, either:',
160
+ '- Run `/bookmark:list` and pick a specific snapshot explicitly',
161
+ '- Read the stale file manually if you still want its content: ' +
162
+ `\`cat "${path}"\``,
163
+ '- Ask the user what they were working on most recently',
164
+ ].join('\n');
165
+ }
166
+ function buildPointerFollowHeader(pointer, canonicalPath, ageHours) {
167
+ const lines = [
168
+ `[Bookmark: followed home-scope pointer → repo-scope bookmark]`,
169
+ '',
170
+ `Canonical file: ${canonicalPath}`,
171
+ ];
172
+ if (pointer.points_to_project) {
173
+ lines.push(`Project: ${pointer.points_to_project}`);
174
+ }
175
+ if (ageHours >= STALENESS_SOFT_WARN_HOURS) {
176
+ lines.push(`Age: ${ageHours}h (approaching staleness threshold of ${STALENESS_HARD_BLOCK_HOURS}h)`);
177
+ }
178
+ return lines.join('\n');
179
+ }
180
+ function buildFallbackRestoration(latestMd, snapshotCount) {
54
181
  const lines = [];
55
182
  lines.push('[Bookmark: Context recovered from previous session]');
56
183
  lines.push('');
57
- lines.push('Briefly notify the user that their prior session context has been recovered by Bookmark.');
58
- lines.push('');
59
- lines.push('## Prior Session Context (Bookmark)');
60
- lines.push('');
61
184
  lines.push(latestMd);
62
- lines.push('');
63
185
  if (snapshotCount > 1) {
64
- lines.push(`> ${snapshotCount} snapshots available. Use \`/bookmark:list\` for history or \`/bookmark:restore\` for a specific snapshot.`);
186
+ lines.push('');
187
+ lines.push(`> ${snapshotCount} snapshots available. \`/bookmark:list\` for history.`);
65
188
  }
66
189
  return lines.join('\n');
67
190
  }
@@ -72,16 +195,13 @@ function handleSessionTransition(storagePath, state, options, thresholds) {
72
195
  switch (source) {
73
196
  case 'startup':
74
197
  case 'clear':
75
- // New session — reset compaction count
76
198
  updatedState = resetForNewSession(state, sessionId, thresholds);
77
199
  break;
78
200
  case 'compact':
79
- // After compaction — increment compaction count
80
201
  updatedState = incrementCompaction(state, thresholds);
81
202
  updatedState.session_id = sessionId;
82
203
  break;
83
204
  case 'resume':
84
- // Resuming — keep state, just update session ID if different
85
205
  updatedState = { ...state, session_id: sessionId, last_event_time: Date.now() };
86
206
  break;
87
207
  default:
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/restore/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/restore/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAC3D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AACxE,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EACL,aAAa,EACb,oBAAoB,EACpB,aAAa,GAEd,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AACtG,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAUlD;;;;;GAKG;AACH,MAAM,0BAA0B,GAAG,EAAE,CAAC;AACtC,MAAM,yBAAyB,GAAG,EAAE,CAAC;AAErC;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,cAAc,CAAC,OAAuB;IACpD,MAAM,MAAM,GAAG,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACvC,MAAM,WAAW,GAAG,cAAc,CAAC,OAAO,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IACxD,MAAM,KAAK,GAAG,SAAS,CAAC,WAAW,CAAC,CAAC;IAErC,uBAAuB,CAAC,WAAW,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC;IAExE,MAAM,iBAAiB,GAAG,IAAI,CAAC,WAAW,EAAE,iBAAiB,CAAC,CAAC;IAC/D,IAAI,UAAU,CAAC,iBAAiB,CAAC,EAAE,CAAC;QAClC,IAAI,CAAC;YAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;IAC/D,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,qBAAqB;QAAE,OAAO,EAAE,CAAC;IAC7C,IAAI,OAAO,CAAC,MAAM,KAAK,QAAQ;QAAE,OAAO,EAAE,CAAC;IAE3C,4DAA4D;IAC5D,MAAM,YAAY,GAAG,aAAa,CAAC,WAAW,CAAC,CAAC;IAChD,IAAI,YAAY,IAAI,iBAAiB,CAAC,YAAY,CAAC,EAAE,CAAC;QACpD,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,EAAE,qBAAqB,CAAC,CAAC;QAC7D,MAAM,EAAE,QAAQ,EAAE,mBAAmB,EAAE,GAAG,aAAa,CAAC,YAAY,CAAC,CAAC;QAEtE,oEAAoE;QACpE,IAAI,QAAQ,EAAE,KAAK,KAAK,MAAM,EAAE,CAAC;YAC/B,MAAM,MAAM,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;YACvC,IAAI,MAAM,EAAE,CAAC;gBACX,MAAM,SAAS,GAAG,MAAM,CAAC,eAAe,IAAI,CAAC,CAAC;gBAC9C,IAAI,SAAS,IAAI,0BAA0B,EAAE,CAAC;oBAC5C,YAAY,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;oBAC7B,OAAO,EAAE,aAAa,EAAE,yBAAyB,CAAC,MAAM,CAAC,cAAc,EAAE,SAAS,CAAC,EAAE,CAAC;gBACxF,CAAC;gBAED,+DAA+D;gBAC/D,MAAM,EAAE,mBAAmB,EAAE,UAAU,EAAE,GAAG,aAAa,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;gBAC1E,MAAM,MAAM,GAAG,wBAAwB,CAAC,QAAQ,EAAE,MAAM,CAAC,cAAc,EAAE,SAAS,CAAC,CAAC;gBACpF,MAAM,OAAO,GAAG,GAAG,MAAM,OAAO,UAAU,EAAE,CAAC;gBAC7C,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;gBAC1C,IAAI,QAAQ,CAAC,mBAAmB,EAAE,CAAC;oBACjC,gBAAgB,CAAC,yBAAyB,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC,CAAC;gBAC5E,CAAC;gBACD,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,CAAC;YACpC,CAAC;YACD,2EAA2E;QAC7E,CAAC;QAED,2BAA2B;QAC3B,MAAM,QAAQ,GAAG,WAAW,CAAC,WAAW,CAAC,CAAC;QAC1C,IAAI,QAAQ,KAAK,IAAI,IAAI,QAAQ,IAAI,0BAA0B,EAAE,CAAC;YAChE,YAAY,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;YAC7B,OAAO,EAAE,aAAa,EAAE,yBAAyB,CAAC,WAAW,EAAE,QAAQ,CAAC,EAAE,CAAC;QAC7E,CAAC;QAED,uDAAuD;QACvD,MAAM,eAAe,GAAG,QAAQ,CAAC,CAAC,CAAC,oBAAoB,CAAC,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAEtF,yBAAyB;QACzB,MAAM,WAAW,GACf,QAAQ,KAAK,IAAI,IAAI,QAAQ,IAAI,yBAAyB;YACxD,CAAC,CAAC,mCAAmC,QAAQ,6BAA6B;YAC1E,CAAC,CAAC,IAAI,CAAC;QAEX,MAAM,QAAQ,GAAG,CAAC,eAAe,EAAE,WAAW,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC7E,MAAM,OAAO,GAAG,QAAQ,CAAC,CAAC,CAAC,GAAG,QAAQ,OAAO,mBAAmB,EAAE,CAAC,CAAC,CAAC,mBAAmB,CAAC;QACzF,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;QAC1C,gBAAgB,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC9B,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,CAAC;IACpC,CAAC;IAED,IAAI,YAAY,EAAE,CAAC;QACjB,sBAAsB,CAAC,WAAW,CAAC,CAAC;IACtC,CAAC;IAED,sBAAsB;IACtB,MAAM,aAAa,GAAG,gBAAgB,CAAC,WAAW,CAAC,CAAC;IACpD,MAAM,QAAQ,GAAG,YAAY,CAAC,WAAW,CAAC,CAAC;IAC3C,IAAI,QAAQ,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,wBAAwB,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;QAClE,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;QAC1C,gBAAgB,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC9B,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,CAAC;IACpC,CAAC;IAED,sEAAsE;IACtE,oFAAoF;IACpF,6EAA6E;IAC7E,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,yEAAyE;AACzE,SAAS,yBAAyB,CAAC,aAAqB;IACtD,0DAA0D;IAC1D,MAAM,MAAM,GAAG,aAAa,CAAC;IAC7B,MAAM,GAAG,GAAG,aAAa,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;IAC9C,OAAO,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC;AAC/D,CAAC;AAED,gEAAgE;AAChE,SAAS,YAAY,CAAC,WAAmB,EAAE,SAAiB;IAC1D,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,SAAS,CAAC,WAAW,CAAC,CAAC;QACrC,KAAK,CAAC,kBAAkB,GAAG,CAAC,KAAK,CAAC,kBAAkB,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;QAC/D,KAAK,CAAC,eAAe,GAAG,CAAC,KAAK,CAAC,eAAe,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC;QACjF,SAAS,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC,CAAC,sCAAsC,CAAC,CAAC;AACpD,CAAC;AAED,SAAS,sBAAsB,CAAC,WAAmB;IACjD,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,SAAS,CAAC,WAAW,CAAC,CAAC;QACrC,KAAK,CAAC,kBAAkB,GAAG,CAAC,KAAK,CAAC,kBAAkB,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;QAC/D,SAAS,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC,CAAC,sCAAsC,CAAC,CAAC;AACpD,CAAC;AAED,SAAS,iBAAiB,CAAC,OAAe;IACxC,IAAI,OAAO,CAAC,MAAM,GAAG,GAAG;QAAE,OAAO,KAAK,CAAC;IACvC,IAAI,OAAO,CAAC,UAAU,CAAC,mBAAmB,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACtF,MAAM,OAAO,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,IAAI,CAAC,CAAC;IACvF,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;AAChD,CAAC;AAED,SAAS,WAAW,CAAC,IAAY;IAC/B,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC;QACrC,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;IAC7D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,yBAAyB,CAAC,IAAY,EAAE,QAAgB;IAC/D,OAAO;QACL,+CAA+C,QAAQ,sBAAsB,0BAA0B,MAAM;QAC7G,EAAE;QACF,wBAAwB,IAAI,0CAA0C;QACtE,mFAAmF;QACnF,EAAE;QACF,qBAAqB;QACrB,gEAAgE;QAChE,gEAAgE;YAC9D,UAAU,IAAI,KAAK;QACrB,wDAAwD;KACzD,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED,SAAS,wBAAwB,CAC/B,OAAyB,EACzB,aAAqB,EACrB,QAAgB;IAEhB,MAAM,KAAK,GAAG;QACZ,+DAA+D;QAC/D,EAAE;QACF,mBAAmB,aAAa,EAAE;KACnC,CAAC;IACF,IAAI,OAAO,CAAC,iBAAiB,EAAE,CAAC;QAC9B,KAAK,CAAC,IAAI,CAAC,YAAY,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAAC;IACtD,CAAC;IACD,IAAI,QAAQ,IAAI,yBAAyB,EAAE,CAAC;QAC1C,KAAK,CAAC,IAAI,CAAC,QAAQ,QAAQ,yCAAyC,0BAA0B,IAAI,CAAC,CAAC;IACtG,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,SAAS,wBAAwB,CAAC,QAAgB,EAAE,aAAqB;IACvE,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,CAAC,IAAI,CAAC,qDAAqD,CAAC,CAAC;IAClE,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACrB,IAAI,aAAa,GAAG,CAAC,EAAE,CAAC;QACtB,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,CAAC,IAAI,CAAC,KAAK,aAAa,uDAAuD,CAAC,CAAC;IACxF,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,SAAS,uBAAuB,CAC9B,WAAmB,EACnB,KAAoB,EACpB,OAAuB,EACvB,UAAoB;IAEpB,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,SAAS,CAAC;IAC3C,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,WAAW,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;IAE/D,IAAI,YAA2B,CAAC;IAEhC,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,SAAS,CAAC;QACf,KAAK,OAAO;YACV,YAAY,GAAG,kBAAkB,CAAC,KAAK,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;YAChE,MAAM;QAER,KAAK,SAAS;YACZ,YAAY,GAAG,mBAAmB,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;YACtD,YAAY,CAAC,UAAU,GAAG,SAAS,CAAC;YACpC,MAAM;QAER,KAAK,QAAQ;YACX,YAAY,GAAG,EAAE,GAAG,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,eAAe,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;YAChF,MAAM;QAER;YACE,YAAY,GAAG,KAAK,CAAC;IACzB,CAAC;IAED,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC;QAAE,OAAO;IACrC,SAAS,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;AACvC,CAAC"}
@@ -1,3 +1,8 @@
1
+ /**
2
+ * Register bookmark in Claude Code's installed_plugins.json.
3
+ * This is required for skill/command discovery — the symlink alone isn't enough.
4
+ */
5
+ export declare function registerPlugin(): boolean;
1
6
  /**
2
7
  * Check if bookmark hooks are already configured in a project.
3
8
  */
@@ -9,8 +14,9 @@ export declare function isProjectConfigured(cwd: string): boolean;
9
14
  */
10
15
  export declare function setupProject(cwd: string): string[];
11
16
  /**
12
- * Auto-bootstrap: silently configure hooks if bookmark CLI runs in an unconfigured project.
13
- * Called at the top of CLI commands. No-op if already configured.
17
+ * Auto-bootstrap: silently configure storage if bookmark CLI runs in an unconfigured project.
18
+ * Called at the top of CLI commands. Creates .bookmark/ if needed.
19
+ * Works in any directory — not just npm projects.
14
20
  */
15
21
  export declare function ensureProjectBootstrapped(cwd: string): void;
16
22
  //# sourceMappingURL=auto-setup.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"auto-setup.d.ts","sourceRoot":"","sources":["../../src/setup/auto-setup.ts"],"names":[],"mappings":"AAqBA;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CASxD;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAgClD;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAW3D"}
1
+ {"version":3,"file":"auto-setup.d.ts","sourceRoot":"","sources":["../../src/setup/auto-setup.ts"],"names":[],"mappings":"AA4BA;;;GAGG;AACH,wBAAgB,cAAc,IAAI,OAAO,CAqDxC;AA+CD;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CASxD;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CA2ClD;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAgB3D"}