dsh-plugin-sessiongraph-sessions 0.1.15 → 0.1.17

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/lib/index.d.ts CHANGED
@@ -103,6 +103,15 @@ export interface Config {
103
103
  * yet this builds the first one; with one already present it refreshes incrementally.
104
104
  */
105
105
  autoIndex?: boolean;
106
+ /**
107
+ * Shortest gap between two automatic refreshes of one index root, in milliseconds (default 60000).
108
+ *
109
+ * The window exists to absorb a burst of session creations into one run — opening five sessions at
110
+ * once must not queue five index jobs. Past it, the next session refreshes, which is what keeps the
111
+ * index current while the desktop stays up: an incremental run against a warm index takes tens of
112
+ * milliseconds and does not block the UI.
113
+ */
114
+ autoIndexMinIntervalMs?: number;
106
115
  /**
107
116
  * Build the very first index automatically in the background when a session starts (default
108
117
  * true). The first build reads every log on the machine and can take seconds to minutes, so it
package/lib/index.js CHANGED
@@ -90,6 +90,7 @@ export const Config = z.object({
90
90
  toolCallChars: z.number().default(DEFAULT_TOOL_CALL_CHARS),
91
91
  maxFileBytes: z.number().default(DEFAULT_MAX_FILE_BYTES),
92
92
  autoIndex: z.boolean().default(true),
93
+ autoIndexMinIntervalMs: z.number().default(60_000),
93
94
  autoBuild: z.boolean().default(true),
94
95
  indexLockStaleMs: z.number().default(300_000),
95
96
  backgroundIndexThreshold: z.number().default(DEFAULT_BACKGROUND_INDEX_THRESHOLD),
@@ -112,16 +113,18 @@ export function apply(ctx, config) {
112
113
  throw new Error('sessiongraph-sessions: indexRoot must be a non-empty directory path');
113
114
  }
114
115
  const indexer = createIndexer(ctx, resolved);
115
- // Process-local, private to this plugin instance: a root is auto-refreshed at most once per
116
- // process, so a burst of session creations cannot queue a burst of index runs.
117
- const autoIndexed = new Set();
116
+ // Process-local, private to this plugin instance: when this root last had an automatic refresh.
117
+ // A time window rather than "once per process": the whole point of the index is that what was just
118
+ // said is findable, and "once until restart" stopped being enough the moment the desktop stayed up
119
+ // for days. The window still absorbs a burst of session creations into one run.
120
+ const autoIndexRuns = new Map();
118
121
  // `agent/created` is typed by the host's agent service; this package reads only the two fields it
119
122
  // needs through a structural face rather than depending on that package.
120
123
  const agentEvents = ctx;
121
124
  ctx.effect(function* () {
122
125
  if (resolved.autoIndex) {
123
126
  yield agentEvents.on('agent/created', payload => {
124
- scheduleAutoIndex(ctx, resolved, autoIndexed, payload);
127
+ scheduleAutoIndex(ctx, resolved, autoIndexRuns, payload);
125
128
  });
126
129
  }
127
130
  yield ctx.sessiongraph.registerIndexer(indexer);
@@ -172,10 +175,10 @@ export function isBackgroundIndexReport(report) {
172
175
  * only decides whether a refresh is warranted and hands one to the host's job registry.
173
176
  * @param ctx - the plugin context, consulted for the optional job registry.
174
177
  * @param config - the resolved plugin configuration.
175
- * @param autoIndexed - index roots this process has already scheduled a refresh for.
178
+ * @param autoIndexRuns - when each root last had an automatic refresh, in epoch milliseconds.
176
179
  * @param payload - the `agent/created` dispatch payload.
177
180
  */
178
- function scheduleAutoIndex(ctx, config, autoIndexed, payload) {
181
+ function scheduleAutoIndex(ctx, config, autoIndexRuns, payload) {
179
182
  try {
180
183
  const agent = payload.agent;
181
184
  const workspace = agent?.session?.header?.cwd;
@@ -183,8 +186,12 @@ function scheduleAutoIndex(ctx, config, autoIndexed, payload) {
183
186
  if (agent === undefined || workspace === undefined || workspace === '')
184
187
  return;
185
188
  const indexRoot = expandHome(config.indexRoot);
186
- // Once per root per process: a burst of session creations must not queue a burst of index runs.
187
- if (autoIndexed.has(indexRoot))
189
+ const now = Date.now();
190
+ // Within the window, a burst of session creations must not queue a burst of index runs. Past it,
191
+ // the next session refreshes: sessions written since the last run are exactly what an incremental
192
+ // index exists to pick up, and it costs tens of milliseconds against a warm cache.
193
+ const previous = autoIndexRuns.get(indexRoot);
194
+ if (previous !== undefined && now - previous < config.autoIndexMinIntervalMs)
188
195
  return;
189
196
  // A first build reads every log on the machine and can take a while, so it stays a background
190
197
  // job like the incremental refresh. `autoBuild: false` restores the stricter behaviour where
@@ -208,7 +215,7 @@ function scheduleAutoIndex(ctx, config, autoIndexed, payload) {
208
215
  });
209
216
  // Marked only after the registry accepted the job, so a refusal leaves the root eligible for
210
217
  // the next session that opens.
211
- autoIndexed.add(indexRoot);
218
+ autoIndexRuns.set(indexRoot, now);
212
219
  }
213
220
  catch (error) {
214
221
  // A throwing listener would veto publication of the agent. Losing a refresh is a degradation,
@@ -442,7 +449,7 @@ async function runNativeEngine(native, indexPath, options, config, inScope, ctx,
442
449
  let nativeReport;
443
450
  try {
444
451
  signal?.throwIfAborted();
445
- nativeReport = native.indexSessions({
452
+ nativeReport = await native.indexSessions({
446
453
  sessionsRoot: config.sessionsRoot,
447
454
  indexPath,
448
455
  ...(options.force === undefined ? {} : { force: options.force }),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-plugin-sessiongraph-sessions",
3
- "version": "0.1.15",
3
+ "version": "0.1.17",
4
4
  "description": "Session-log indexer for DeepSeek Harness — scans ~/.dsh/sessions, decompresses the multi-frame zstd JSONL logs and writes the sessiongraph SQLite index the store reads",
5
5
  "keywords": [
6
6
  "dsh",
@@ -49,8 +49,8 @@
49
49
  },
50
50
  "dependencies": {
51
51
  "@deepseek-ai/schemastery": "^3.18.1",
52
- "dsh-plugin-sessiongraph-service": "^0.1.15",
53
- "dsh-plugin-sessiongraph-native": "^0.1.15"
52
+ "dsh-plugin-sessiongraph-service": "^0.1.17",
53
+ "dsh-plugin-sessiongraph-native": "^0.1.17"
54
54
  },
55
55
  "peerDependencies": {
56
56
  "@deepseek-ai/cordis": ">=4.0.1",