context-vault 3.1.6 → 3.1.7
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/bin/cli.js +1369 -1774
- package/node_modules/@context-vault/core/dist/capture.d.ts +1 -1
- package/node_modules/@context-vault/core/dist/capture.d.ts.map +1 -1
- package/node_modules/@context-vault/core/dist/capture.js +34 -47
- package/node_modules/@context-vault/core/dist/capture.js.map +1 -1
- package/node_modules/@context-vault/core/dist/categories.js +30 -30
- package/node_modules/@context-vault/core/dist/config.d.ts +1 -1
- package/node_modules/@context-vault/core/dist/config.d.ts.map +1 -1
- package/node_modules/@context-vault/core/dist/config.js +37 -43
- package/node_modules/@context-vault/core/dist/config.js.map +1 -1
- package/node_modules/@context-vault/core/dist/constants.d.ts.map +1 -1
- package/node_modules/@context-vault/core/dist/constants.js +4 -4
- package/node_modules/@context-vault/core/dist/constants.js.map +1 -1
- package/node_modules/@context-vault/core/dist/db.d.ts +2 -2
- package/node_modules/@context-vault/core/dist/db.d.ts.map +1 -1
- package/node_modules/@context-vault/core/dist/db.js +21 -20
- package/node_modules/@context-vault/core/dist/db.js.map +1 -1
- package/node_modules/@context-vault/core/dist/embed.d.ts.map +1 -1
- package/node_modules/@context-vault/core/dist/embed.js +11 -11
- package/node_modules/@context-vault/core/dist/embed.js.map +1 -1
- package/node_modules/@context-vault/core/dist/files.d.ts.map +1 -1
- package/node_modules/@context-vault/core/dist/files.js +12 -13
- package/node_modules/@context-vault/core/dist/files.js.map +1 -1
- package/node_modules/@context-vault/core/dist/formatters.js +5 -5
- package/node_modules/@context-vault/core/dist/frontmatter.d.ts.map +1 -1
- package/node_modules/@context-vault/core/dist/frontmatter.js +23 -23
- package/node_modules/@context-vault/core/dist/frontmatter.js.map +1 -1
- package/node_modules/@context-vault/core/dist/index.d.ts +1 -1
- package/node_modules/@context-vault/core/dist/index.d.ts.map +1 -1
- package/node_modules/@context-vault/core/dist/index.js +58 -46
- package/node_modules/@context-vault/core/dist/index.js.map +1 -1
- package/node_modules/@context-vault/core/dist/ingest-url.d.ts.map +1 -1
- package/node_modules/@context-vault/core/dist/ingest-url.js +30 -33
- package/node_modules/@context-vault/core/dist/ingest-url.js.map +1 -1
- package/node_modules/@context-vault/core/dist/main.d.ts +13 -13
- package/node_modules/@context-vault/core/dist/main.d.ts.map +1 -1
- package/node_modules/@context-vault/core/dist/main.js +12 -12
- package/node_modules/@context-vault/core/dist/main.js.map +1 -1
- package/node_modules/@context-vault/core/dist/search.d.ts +1 -1
- package/node_modules/@context-vault/core/dist/search.d.ts.map +1 -1
- package/node_modules/@context-vault/core/dist/search.js +20 -22
- package/node_modules/@context-vault/core/dist/search.js.map +1 -1
- package/node_modules/@context-vault/core/dist/types.d.ts +1 -1
- package/node_modules/@context-vault/core/package.json +1 -1
- package/node_modules/@context-vault/core/src/capture.ts +44 -81
- package/node_modules/@context-vault/core/src/categories.ts +30 -30
- package/node_modules/@context-vault/core/src/config.ts +45 -60
- package/node_modules/@context-vault/core/src/constants.ts +8 -10
- package/node_modules/@context-vault/core/src/db.ts +37 -56
- package/node_modules/@context-vault/core/src/embed.ts +15 -26
- package/node_modules/@context-vault/core/src/files.ts +13 -16
- package/node_modules/@context-vault/core/src/formatters.ts +5 -5
- package/node_modules/@context-vault/core/src/frontmatter.ts +26 -30
- package/node_modules/@context-vault/core/src/index.ts +94 -100
- package/node_modules/@context-vault/core/src/ingest-url.ts +56 -93
- package/node_modules/@context-vault/core/src/main.ts +13 -18
- package/node_modules/@context-vault/core/src/search.ts +34 -56
- package/node_modules/@context-vault/core/src/types.ts +1 -1
- package/package.json +2 -2
- package/scripts/postinstall.js +18 -25
- package/scripts/prepack.js +13 -19
- package/src/archive.js +211 -0
- package/src/error-log.js +7 -7
- package/src/helpers.js +11 -13
- package/src/linking.js +8 -11
- package/src/migrate-dirs.js +139 -0
- package/src/register-tools.js +46 -48
- package/src/server.js +73 -99
- package/src/status.js +35 -71
- package/src/telemetry.js +18 -22
- package/src/temporal.js +19 -30
- package/src/tools/clear-context.js +15 -18
- package/src/tools/context-status.js +37 -57
- package/src/tools/create-snapshot.js +45 -57
- package/src/tools/delete-context.js +11 -12
- package/src/tools/get-context.js +112 -160
- package/src/tools/ingest-project.js +66 -86
- package/src/tools/ingest-url.js +25 -41
- package/src/tools/list-buckets.js +19 -25
- package/src/tools/list-context.js +35 -58
- package/src/tools/save-context.js +126 -182
- package/src/tools/session-start.js +46 -62
package/src/status.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { existsSync, readdirSync, statSync } from
|
|
2
|
-
import { join } from
|
|
3
|
-
import { walkDir } from
|
|
4
|
-
import { isEmbedAvailable } from
|
|
5
|
-
import { KIND_STALENESS_DAYS } from
|
|
1
|
+
import { existsSync, readdirSync, statSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { walkDir } from '@context-vault/core/files';
|
|
4
|
+
import { isEmbedAvailable } from '@context-vault/core/embed';
|
|
5
|
+
import { KIND_STALENESS_DAYS } from '@context-vault/core/categories';
|
|
6
6
|
|
|
7
7
|
function countArchivedEntries(vaultDir) {
|
|
8
|
-
const archRoot = join(vaultDir,
|
|
8
|
+
const archRoot = join(vaultDir, '_archive');
|
|
9
9
|
if (!existsSync(archRoot)) return 0;
|
|
10
10
|
try {
|
|
11
11
|
return walkDir(archRoot).length;
|
|
@@ -37,9 +37,7 @@ export function gatherVaultStatus(ctx, opts = {}) {
|
|
|
37
37
|
|
|
38
38
|
let kindCounts = [];
|
|
39
39
|
try {
|
|
40
|
-
kindCounts = db
|
|
41
|
-
.prepare(`SELECT kind, COUNT(*) as c FROM vault GROUP BY kind`)
|
|
42
|
-
.all();
|
|
40
|
+
kindCounts = db.prepare(`SELECT kind, COUNT(*) as c FROM vault GROUP BY kind`).all();
|
|
43
41
|
} catch (e) {
|
|
44
42
|
errors.push(`Kind count query failed: ${e.message}`);
|
|
45
43
|
}
|
|
@@ -53,7 +51,7 @@ export function gatherVaultStatus(ctx, opts = {}) {
|
|
|
53
51
|
errors.push(`Category count query failed: ${e.message}`);
|
|
54
52
|
}
|
|
55
53
|
|
|
56
|
-
let dbSize =
|
|
54
|
+
let dbSize = 'n/a';
|
|
57
55
|
let dbSizeBytes = 0;
|
|
58
56
|
try {
|
|
59
57
|
if (existsSync(config.dbPath)) {
|
|
@@ -71,9 +69,7 @@ export function gatherVaultStatus(ctx, opts = {}) {
|
|
|
71
69
|
let staleCount = 0;
|
|
72
70
|
try {
|
|
73
71
|
const result = db
|
|
74
|
-
.prepare(
|
|
75
|
-
`SELECT COUNT(*) as c FROM vault WHERE file_path NOT LIKE ? || '%'`,
|
|
76
|
-
)
|
|
72
|
+
.prepare(`SELECT COUNT(*) as c FROM vault WHERE file_path NOT LIKE ? || '%'`)
|
|
77
73
|
.get(config.vaultDir);
|
|
78
74
|
staleCount = result.c;
|
|
79
75
|
stalePaths = staleCount > 0;
|
|
@@ -85,7 +81,7 @@ export function gatherVaultStatus(ctx, opts = {}) {
|
|
|
85
81
|
try {
|
|
86
82
|
expiredCount = db
|
|
87
83
|
.prepare(
|
|
88
|
-
`SELECT COUNT(*) as c FROM vault WHERE expires_at IS NOT NULL AND expires_at <= datetime('now')
|
|
84
|
+
`SELECT COUNT(*) as c FROM vault WHERE expires_at IS NOT NULL AND expires_at <= datetime('now')`
|
|
89
85
|
)
|
|
90
86
|
.get().c;
|
|
91
87
|
} catch (e) {
|
|
@@ -94,9 +90,7 @@ export function gatherVaultStatus(ctx, opts = {}) {
|
|
|
94
90
|
|
|
95
91
|
let eventCount = 0;
|
|
96
92
|
try {
|
|
97
|
-
eventCount = db
|
|
98
|
-
.prepare(`SELECT COUNT(*) as c FROM vault WHERE category = 'event'`)
|
|
99
|
-
.get().c;
|
|
93
|
+
eventCount = db.prepare(`SELECT COUNT(*) as c FROM vault WHERE category = 'event'`).get().c;
|
|
100
94
|
} catch (e) {
|
|
101
95
|
errors.push(`Event count failed: ${e.message}`);
|
|
102
96
|
}
|
|
@@ -104,9 +98,7 @@ export function gatherVaultStatus(ctx, opts = {}) {
|
|
|
104
98
|
let eventsWithoutTtlCount = 0;
|
|
105
99
|
try {
|
|
106
100
|
eventsWithoutTtlCount = db
|
|
107
|
-
.prepare(
|
|
108
|
-
`SELECT COUNT(*) as c FROM vault WHERE category = 'event' AND expires_at IS NULL`,
|
|
109
|
-
)
|
|
101
|
+
.prepare(`SELECT COUNT(*) as c FROM vault WHERE category = 'event' AND expires_at IS NULL`)
|
|
110
102
|
.get().c;
|
|
111
103
|
} catch (e) {
|
|
112
104
|
errors.push(`Events without TTL count failed: ${e.message}`);
|
|
@@ -116,9 +108,7 @@ export function gatherVaultStatus(ctx, opts = {}) {
|
|
|
116
108
|
try {
|
|
117
109
|
const total = db.prepare(`SELECT COUNT(*) as c FROM vault`).get().c;
|
|
118
110
|
const indexed = db
|
|
119
|
-
.prepare(
|
|
120
|
-
`SELECT COUNT(*) as c FROM vault WHERE rowid IN (SELECT rowid FROM vault_vec)`,
|
|
121
|
-
)
|
|
111
|
+
.prepare(`SELECT COUNT(*) as c FROM vault WHERE rowid IN (SELECT rowid FROM vault_vec)`)
|
|
122
112
|
.get().c;
|
|
123
113
|
embeddingStatus = { indexed, total, missing: total - indexed };
|
|
124
114
|
} catch (e) {
|
|
@@ -131,7 +121,7 @@ export function gatherVaultStatus(ctx, opts = {}) {
|
|
|
131
121
|
try {
|
|
132
122
|
autoCapturedFeedbackCount = db
|
|
133
123
|
.prepare(
|
|
134
|
-
`SELECT COUNT(*) as c FROM vault WHERE kind = 'feedback' AND tags LIKE '%"auto-captured"%'
|
|
124
|
+
`SELECT COUNT(*) as c FROM vault WHERE kind = 'feedback' AND tags LIKE '%"auto-captured"%'`
|
|
135
125
|
)
|
|
136
126
|
.get().c;
|
|
137
127
|
} catch (e) {
|
|
@@ -152,12 +142,12 @@ export function gatherVaultStatus(ctx, opts = {}) {
|
|
|
152
142
|
const kindClauses = stalenessKinds
|
|
153
143
|
.map(
|
|
154
144
|
([kind, days]) =>
|
|
155
|
-
`(kind = '${kind}' AND COALESCE(updated_at, created_at) <= datetime('now', '-${days} days'))
|
|
145
|
+
`(kind = '${kind}' AND COALESCE(updated_at, created_at) <= datetime('now', '-${days} days'))`
|
|
156
146
|
)
|
|
157
|
-
.join(
|
|
147
|
+
.join(' OR ');
|
|
158
148
|
staleKnowledge = db
|
|
159
149
|
.prepare(
|
|
160
|
-
`SELECT kind, title, COALESCE(updated_at, created_at) as last_updated FROM vault WHERE category = 'knowledge' AND (${kindClauses}) AND (expires_at IS NULL OR expires_at > datetime('now')) ORDER BY last_updated ASC LIMIT 10
|
|
150
|
+
`SELECT kind, title, COALESCE(updated_at, created_at) as last_updated FROM vault WHERE category = 'knowledge' AND (${kindClauses}) AND (expires_at IS NULL OR expires_at > datetime('now')) ORDER BY last_updated ASC LIMIT 10`
|
|
161
151
|
)
|
|
162
152
|
.all();
|
|
163
153
|
}
|
|
@@ -202,84 +192,62 @@ export function computeGrowthWarnings(status, thresholds) {
|
|
|
202
192
|
const actions = [];
|
|
203
193
|
|
|
204
194
|
const total = status.embeddingStatus?.total ?? 0;
|
|
205
|
-
const {
|
|
206
|
-
eventCount = 0,
|
|
207
|
-
eventsWithoutTtlCount = 0,
|
|
208
|
-
expiredCount = 0,
|
|
209
|
-
dbSizeBytes = 0,
|
|
210
|
-
} = status;
|
|
195
|
+
const { eventCount = 0, eventsWithoutTtlCount = 0, expiredCount = 0, dbSizeBytes = 0 } = status;
|
|
211
196
|
|
|
212
197
|
let totalExceeded = false;
|
|
213
198
|
|
|
214
199
|
if (t.totalEntries?.critical != null && total >= t.totalEntries.critical) {
|
|
215
200
|
totalExceeded = true;
|
|
216
201
|
warnings.push({
|
|
217
|
-
level:
|
|
202
|
+
level: 'critical',
|
|
218
203
|
message: `Total entries: ${total.toLocaleString()} (exceeds critical limit of ${t.totalEntries.critical.toLocaleString()})`,
|
|
219
204
|
});
|
|
220
205
|
} else if (t.totalEntries?.warn != null && total >= t.totalEntries.warn) {
|
|
221
206
|
totalExceeded = true;
|
|
222
207
|
warnings.push({
|
|
223
|
-
level:
|
|
208
|
+
level: 'warn',
|
|
224
209
|
message: `Total entries: ${total.toLocaleString()} (exceeds recommended ${t.totalEntries.warn.toLocaleString()})`,
|
|
225
210
|
});
|
|
226
211
|
}
|
|
227
212
|
|
|
228
|
-
if (
|
|
229
|
-
t.eventEntries?.critical != null &&
|
|
230
|
-
eventCount >= t.eventEntries.critical
|
|
231
|
-
) {
|
|
213
|
+
if (t.eventEntries?.critical != null && eventCount >= t.eventEntries.critical) {
|
|
232
214
|
warnings.push({
|
|
233
|
-
level:
|
|
215
|
+
level: 'critical',
|
|
234
216
|
message: `Event entries: ${eventCount.toLocaleString()} (exceeds critical limit of ${t.eventEntries.critical.toLocaleString()})`,
|
|
235
217
|
});
|
|
236
|
-
} else if (
|
|
237
|
-
t.eventEntries?.warn != null &&
|
|
238
|
-
eventCount >= t.eventEntries.warn
|
|
239
|
-
) {
|
|
218
|
+
} else if (t.eventEntries?.warn != null && eventCount >= t.eventEntries.warn) {
|
|
240
219
|
const ttlNote =
|
|
241
|
-
eventsWithoutTtlCount > 0
|
|
242
|
-
? ` (${eventsWithoutTtlCount.toLocaleString()} without TTL)`
|
|
243
|
-
: "";
|
|
220
|
+
eventsWithoutTtlCount > 0 ? ` (${eventsWithoutTtlCount.toLocaleString()} without TTL)` : '';
|
|
244
221
|
warnings.push({
|
|
245
|
-
level:
|
|
222
|
+
level: 'warn',
|
|
246
223
|
message: `Event entries: ${eventCount.toLocaleString()}${ttlNote} (exceeds recommended ${t.eventEntries.warn.toLocaleString()})`,
|
|
247
224
|
});
|
|
248
225
|
}
|
|
249
226
|
|
|
250
|
-
if (
|
|
251
|
-
t.vaultSizeBytes?.critical != null &&
|
|
252
|
-
dbSizeBytes >= t.vaultSizeBytes.critical
|
|
253
|
-
) {
|
|
227
|
+
if (t.vaultSizeBytes?.critical != null && dbSizeBytes >= t.vaultSizeBytes.critical) {
|
|
254
228
|
warnings.push({
|
|
255
|
-
level:
|
|
229
|
+
level: 'critical',
|
|
256
230
|
message: `Database size: ${(dbSizeBytes / 1024 / 1024).toFixed(1)}MB (exceeds critical limit of ${(t.vaultSizeBytes.critical / 1024 / 1024).toFixed(0)}MB)`,
|
|
257
231
|
});
|
|
258
|
-
} else if (
|
|
259
|
-
t.vaultSizeBytes?.warn != null &&
|
|
260
|
-
dbSizeBytes >= t.vaultSizeBytes.warn
|
|
261
|
-
) {
|
|
232
|
+
} else if (t.vaultSizeBytes?.warn != null && dbSizeBytes >= t.vaultSizeBytes.warn) {
|
|
262
233
|
warnings.push({
|
|
263
|
-
level:
|
|
234
|
+
level: 'warn',
|
|
264
235
|
message: `Database size: ${(dbSizeBytes / 1024 / 1024).toFixed(1)}MB (exceeds recommended ${(t.vaultSizeBytes.warn / 1024 / 1024).toFixed(0)}MB)`,
|
|
265
236
|
});
|
|
266
237
|
}
|
|
267
238
|
|
|
268
|
-
if (
|
|
269
|
-
t.eventsWithoutTtl?.warn != null &&
|
|
270
|
-
eventsWithoutTtlCount >= t.eventsWithoutTtl.warn
|
|
271
|
-
) {
|
|
239
|
+
if (t.eventsWithoutTtl?.warn != null && eventsWithoutTtlCount >= t.eventsWithoutTtl.warn) {
|
|
272
240
|
warnings.push({
|
|
273
|
-
level:
|
|
241
|
+
level: 'warn',
|
|
274
242
|
message: `Event entries without expires_at: ${eventsWithoutTtlCount.toLocaleString()} (exceeds recommended ${t.eventsWithoutTtl.warn.toLocaleString()})`,
|
|
275
243
|
});
|
|
276
244
|
}
|
|
277
245
|
|
|
278
|
-
const hasCritical = warnings.some((w) => w.level ===
|
|
246
|
+
const hasCritical = warnings.some((w) => w.level === 'critical');
|
|
279
247
|
|
|
280
248
|
if (expiredCount > 0) {
|
|
281
249
|
actions.push(
|
|
282
|
-
`Run \`context-vault prune\` to remove ${expiredCount} expired event entr${expiredCount === 1 ?
|
|
250
|
+
`Run \`context-vault prune\` to remove ${expiredCount} expired event entr${expiredCount === 1 ? 'y' : 'ies'}`
|
|
283
251
|
);
|
|
284
252
|
}
|
|
285
253
|
if (
|
|
@@ -287,14 +255,10 @@ export function computeGrowthWarnings(status, thresholds) {
|
|
|
287
255
|
(eventCount >= (t.eventEntries?.warn ?? Infinity) ||
|
|
288
256
|
eventsWithoutTtlCount >= (t.eventsWithoutTtl?.warn ?? Infinity))
|
|
289
257
|
) {
|
|
290
|
-
actions.push(
|
|
291
|
-
"Add `expires_at` to event/session entries to enable automatic cleanup",
|
|
292
|
-
);
|
|
258
|
+
actions.push('Add `expires_at` to event/session entries to enable automatic cleanup');
|
|
293
259
|
}
|
|
294
260
|
if (total >= (t.totalEntries?.warn ?? Infinity)) {
|
|
295
|
-
actions.push(
|
|
296
|
-
"Run `context-vault archive` to move old ephemeral/event entries to _archive/",
|
|
297
|
-
);
|
|
261
|
+
actions.push('Run `context-vault archive` to move old ephemeral/event entries to _archive/');
|
|
298
262
|
}
|
|
299
263
|
|
|
300
264
|
const kindBreakdown =
|
package/src/telemetry.js
CHANGED
|
@@ -1,18 +1,14 @@
|
|
|
1
|
-
import { existsSync, writeFileSync } from
|
|
2
|
-
import { join } from
|
|
3
|
-
import {
|
|
4
|
-
API_URL,
|
|
5
|
-
MARKETING_URL,
|
|
6
|
-
GITHUB_ISSUES_URL,
|
|
7
|
-
} from "@context-vault/core/constants";
|
|
1
|
+
import { existsSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { API_URL, MARKETING_URL, GITHUB_ISSUES_URL } from '@context-vault/core/constants';
|
|
8
4
|
|
|
9
5
|
const TELEMETRY_ENDPOINT = `${API_URL}/telemetry`;
|
|
10
|
-
const NOTICE_MARKER =
|
|
11
|
-
const FEEDBACK_PROMPT_MARKER =
|
|
6
|
+
const NOTICE_MARKER = '.telemetry-notice-shown';
|
|
7
|
+
const FEEDBACK_PROMPT_MARKER = '.feedback-prompt-shown';
|
|
12
8
|
|
|
13
9
|
export function isTelemetryEnabled(config) {
|
|
14
10
|
const envVal = process.env.CONTEXT_VAULT_TELEMETRY;
|
|
15
|
-
if (envVal !== undefined) return envVal ===
|
|
11
|
+
if (envVal !== undefined) return envVal === '1' || envVal === 'true';
|
|
16
12
|
return config?.telemetry === true;
|
|
17
13
|
}
|
|
18
14
|
|
|
@@ -31,8 +27,8 @@ export function sendTelemetryEvent(config, payload) {
|
|
|
31
27
|
};
|
|
32
28
|
|
|
33
29
|
fetch(TELEMETRY_ENDPOINT, {
|
|
34
|
-
method:
|
|
35
|
-
headers: {
|
|
30
|
+
method: 'POST',
|
|
31
|
+
headers: { 'Content-Type': 'application/json' },
|
|
36
32
|
body: JSON.stringify(event),
|
|
37
33
|
signal: AbortSignal.timeout(5000),
|
|
38
34
|
}).catch(() => {});
|
|
@@ -42,21 +38,21 @@ export function maybeShowTelemetryNotice(dataDir) {
|
|
|
42
38
|
try {
|
|
43
39
|
const markerPath = join(dataDir, NOTICE_MARKER);
|
|
44
40
|
if (existsSync(markerPath)) return;
|
|
45
|
-
writeFileSync(markerPath, new Date().toISOString() +
|
|
41
|
+
writeFileSync(markerPath, new Date().toISOString() + '\n');
|
|
46
42
|
} catch {
|
|
47
43
|
return;
|
|
48
44
|
}
|
|
49
45
|
|
|
50
46
|
const lines = [
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
47
|
+
'[context-vault] Telemetry: disabled by default.',
|
|
48
|
+
'[context-vault] To help improve context-vault, you can opt in to anonymous error reporting.',
|
|
49
|
+
'[context-vault] Reports contain only: event type, error code, tool name, version, node version, platform, arch, timestamp.',
|
|
50
|
+
'[context-vault] No vault content, file paths, or personal data is ever sent.',
|
|
55
51
|
'[context-vault] Opt in: set "telemetry": true in ~/.context-mcp/config.json or set CONTEXT_VAULT_TELEMETRY=1.',
|
|
56
52
|
`[context-vault] Full payload schema: ${MARKETING_URL}/telemetry`,
|
|
57
53
|
];
|
|
58
54
|
for (const line of lines) {
|
|
59
|
-
process.stderr.write(line +
|
|
55
|
+
process.stderr.write(line + '\n');
|
|
60
56
|
}
|
|
61
57
|
}
|
|
62
58
|
|
|
@@ -64,17 +60,17 @@ export function maybeShowFeedbackPrompt(dataDir) {
|
|
|
64
60
|
try {
|
|
65
61
|
const markerPath = join(dataDir, FEEDBACK_PROMPT_MARKER);
|
|
66
62
|
if (existsSync(markerPath)) return;
|
|
67
|
-
writeFileSync(markerPath, new Date().toISOString() +
|
|
63
|
+
writeFileSync(markerPath, new Date().toISOString() + '\n');
|
|
68
64
|
} catch {
|
|
69
65
|
return;
|
|
70
66
|
}
|
|
71
67
|
|
|
72
68
|
const lines = [
|
|
73
|
-
|
|
74
|
-
|
|
69
|
+
'[context-vault] First entry saved — nice work!',
|
|
70
|
+
'[context-vault] Got feedback, a bug, or a feature request?',
|
|
75
71
|
`[context-vault] Open an issue: ${GITHUB_ISSUES_URL}`,
|
|
76
72
|
];
|
|
77
73
|
for (const line of lines) {
|
|
78
|
-
process.stderr.write(line +
|
|
74
|
+
process.stderr.write(line + '\n');
|
|
79
75
|
}
|
|
80
76
|
}
|
package/src/temporal.js
CHANGED
|
@@ -7,12 +7,12 @@ function startOfToday(now) {
|
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
export function resolveTemporalShortcut(role, value, now = new Date()) {
|
|
10
|
-
if (!value || typeof value !==
|
|
11
|
-
const trimmed = value.trim().toLowerCase().replace(/\s+/g,
|
|
10
|
+
if (!value || typeof value !== 'string') return value;
|
|
11
|
+
const trimmed = value.trim().toLowerCase().replace(/\s+/g, '_');
|
|
12
12
|
|
|
13
|
-
if (trimmed ===
|
|
13
|
+
if (trimmed === 'today') {
|
|
14
14
|
const start = startOfToday(now);
|
|
15
|
-
if (role ===
|
|
15
|
+
if (role === 'until') {
|
|
16
16
|
const end = new Date(start);
|
|
17
17
|
end.setUTCDate(end.getUTCDate() + 1);
|
|
18
18
|
return end.toISOString();
|
|
@@ -20,42 +20,40 @@ export function resolveTemporalShortcut(role, value, now = new Date()) {
|
|
|
20
20
|
return start.toISOString();
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
if (trimmed ===
|
|
23
|
+
if (trimmed === 'yesterday') {
|
|
24
24
|
const todayStart = startOfToday(now);
|
|
25
25
|
const yesterdayStart = new Date(todayStart);
|
|
26
26
|
yesterdayStart.setUTCDate(yesterdayStart.getUTCDate() - 1);
|
|
27
|
-
if (role ===
|
|
27
|
+
if (role === 'since') return yesterdayStart.toISOString();
|
|
28
28
|
return todayStart.toISOString();
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
if (trimmed ===
|
|
31
|
+
if (trimmed === 'this_week') {
|
|
32
32
|
const todayStart = startOfToday(now);
|
|
33
33
|
const dayOfWeek = todayStart.getUTCDay();
|
|
34
34
|
const daysFromMonday = (dayOfWeek + 6) % 7;
|
|
35
35
|
const monday = new Date(todayStart);
|
|
36
36
|
monday.setUTCDate(monday.getUTCDate() - daysFromMonday);
|
|
37
|
-
if (role ===
|
|
37
|
+
if (role === 'since') return monday.toISOString();
|
|
38
38
|
const endOfToday = new Date(todayStart);
|
|
39
39
|
endOfToday.setUTCDate(endOfToday.getUTCDate() + 1);
|
|
40
40
|
return endOfToday.toISOString();
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
if (trimmed ===
|
|
43
|
+
if (trimmed === 'this_month') {
|
|
44
44
|
const d = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1));
|
|
45
|
-
if (role ===
|
|
46
|
-
const endOfMonth = new Date(
|
|
47
|
-
Date.UTC(now.getUTCFullYear(), now.getUTCMonth() + 1, 1),
|
|
48
|
-
);
|
|
45
|
+
if (role === 'since') return d.toISOString();
|
|
46
|
+
const endOfMonth = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth() + 1, 1));
|
|
49
47
|
return endOfMonth.toISOString();
|
|
50
48
|
}
|
|
51
49
|
|
|
52
50
|
const m = SHORTCUT_RE.exec(trimmed);
|
|
53
51
|
if (m) {
|
|
54
52
|
const n = parseInt(m[1], 10);
|
|
55
|
-
const unit = m[2].replace(/s$/,
|
|
53
|
+
const unit = m[2].replace(/s$/, '');
|
|
56
54
|
let ms;
|
|
57
|
-
if (unit ===
|
|
58
|
-
else if (unit ===
|
|
55
|
+
if (unit === 'day') ms = n * 86400000;
|
|
56
|
+
else if (unit === 'week') ms = n * 7 * 86400000;
|
|
59
57
|
else ms = n * 30 * 86400000;
|
|
60
58
|
const target = new Date(now.getTime() - ms);
|
|
61
59
|
target.setUTCHours(0, 0, 0, 0);
|
|
@@ -68,23 +66,14 @@ export function resolveTemporalShortcut(role, value, now = new Date()) {
|
|
|
68
66
|
export function resolveTemporalParams(params, now = new Date()) {
|
|
69
67
|
let { since, until } = params;
|
|
70
68
|
|
|
71
|
-
if (
|
|
72
|
-
since
|
|
73
|
-
|
|
74
|
-
) {
|
|
75
|
-
since = resolveTemporalShortcut("since", since, now);
|
|
76
|
-
until = resolveTemporalShortcut("until", "yesterday", now);
|
|
69
|
+
if (since?.trim().toLowerCase() === 'yesterday' && (until === undefined || until === null)) {
|
|
70
|
+
since = resolveTemporalShortcut('since', since, now);
|
|
71
|
+
until = resolveTemporalShortcut('until', 'yesterday', now);
|
|
77
72
|
return { since, until };
|
|
78
73
|
}
|
|
79
74
|
|
|
80
75
|
return {
|
|
81
|
-
since:
|
|
82
|
-
|
|
83
|
-
? resolveTemporalShortcut("since", since, now)
|
|
84
|
-
: since,
|
|
85
|
-
until:
|
|
86
|
-
until !== undefined
|
|
87
|
-
? resolveTemporalShortcut("until", until, now)
|
|
88
|
-
: until,
|
|
76
|
+
since: since !== undefined ? resolveTemporalShortcut('since', since, now) : since,
|
|
77
|
+
until: until !== undefined ? resolveTemporalShortcut('until', until, now) : until,
|
|
89
78
|
};
|
|
90
79
|
}
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import { z } from
|
|
2
|
-
import { ok } from
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { ok } from '../helpers.js';
|
|
3
3
|
|
|
4
|
-
export const name =
|
|
4
|
+
export const name = 'clear_context';
|
|
5
5
|
|
|
6
6
|
export const description =
|
|
7
|
-
|
|
7
|
+
'Reset active in-memory session context without deleting vault entries. Call this when switching projects or topics mid-session. With `scope`, all subsequent get_context calls should filter to that tag/project. Vault data is never modified.';
|
|
8
8
|
|
|
9
9
|
export const inputSchema = {
|
|
10
10
|
scope: z
|
|
11
11
|
.string()
|
|
12
12
|
.optional()
|
|
13
13
|
.describe(
|
|
14
|
-
|
|
14
|
+
'Optional tag or project name to focus on going forward. When provided, treat subsequent get_context calls as if filtered to this tag.'
|
|
15
15
|
),
|
|
16
16
|
};
|
|
17
17
|
|
|
@@ -21,27 +21,24 @@ export const inputSchema = {
|
|
|
21
21
|
*/
|
|
22
22
|
export function handler({ scope } = {}) {
|
|
23
23
|
const lines = [
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
24
|
+
'## Context Reset',
|
|
25
|
+
'',
|
|
26
|
+
'Active session context has been cleared. All previous context from this session should be disregarded.',
|
|
27
|
+
'',
|
|
28
|
+
'Vault entries are unchanged — no data was deleted.',
|
|
29
29
|
];
|
|
30
30
|
|
|
31
31
|
if (scope?.trim()) {
|
|
32
32
|
const trimmed = scope.trim();
|
|
33
33
|
lines.push(
|
|
34
|
-
|
|
34
|
+
'',
|
|
35
35
|
`### Active Scope: \`${trimmed}\``,
|
|
36
|
-
|
|
37
|
-
`Going forward, treat \`get_context\` calls as scoped to the tag or project **"${trimmed}"** unless the user explicitly requests a different scope or passes their own tag filters
|
|
36
|
+
'',
|
|
37
|
+
`Going forward, treat \`get_context\` calls as scoped to the tag or project **"${trimmed}"** unless the user explicitly requests a different scope or passes their own tag filters.`
|
|
38
38
|
);
|
|
39
39
|
} else {
|
|
40
|
-
lines.push(
|
|
41
|
-
"",
|
|
42
|
-
"No scope set. Use `get_context` normally — all vault entries are accessible.",
|
|
43
|
-
);
|
|
40
|
+
lines.push('', 'No scope set. Use `get_context` normally — all vault entries are accessible.');
|
|
44
41
|
}
|
|
45
42
|
|
|
46
|
-
return ok(lines.join(
|
|
43
|
+
return ok(lines.join('\n'));
|
|
47
44
|
}
|