dsh-plugin-sessiongraph-sessions 0.1.18 → 0.1.20
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 +5 -3
- package/lib/index.js +46 -24
- package/package.json +3 -3
package/lib/index.d.ts
CHANGED
|
@@ -16,9 +16,11 @@
|
|
|
16
16
|
*
|
|
17
17
|
* Every session creation also does indexing work in the background (`agent/created`, `autoIndex`):
|
|
18
18
|
* an existing index is refreshed incrementally, and a missing one is built from scratch (`autoBuild`,
|
|
19
|
-
* default true) so a fresh install becomes searchable without the user running anything.
|
|
20
|
-
*
|
|
21
|
-
*
|
|
19
|
+
* default true) so a fresh install becomes searchable without the user running anything. Those runs
|
|
20
|
+
* are plain background promises, not host jobs: a registered job reports its settlement back to the
|
|
21
|
+
* owning agent, which would put an unasked-for maintenance notice into the transcript and (under the
|
|
22
|
+
* host's default `wakeup` delivery) open a turn of its own. `autoBuild: false` restores the stricter
|
|
23
|
+
* behaviour where nothing is indexed until the caller asks for it.
|
|
22
24
|
*
|
|
23
25
|
* Sessions the host still holds in memory (`ctx.sessionQuery`) are indexed as well, in a second pass
|
|
24
26
|
* after the file-path transaction commits: a conversation that is still running has no log on disk
|
package/lib/index.js
CHANGED
|
@@ -16,9 +16,11 @@
|
|
|
16
16
|
*
|
|
17
17
|
* Every session creation also does indexing work in the background (`agent/created`, `autoIndex`):
|
|
18
18
|
* an existing index is refreshed incrementally, and a missing one is built from scratch (`autoBuild`,
|
|
19
|
-
* default true) so a fresh install becomes searchable without the user running anything.
|
|
20
|
-
*
|
|
21
|
-
*
|
|
19
|
+
* default true) so a fresh install becomes searchable without the user running anything. Those runs
|
|
20
|
+
* are plain background promises, not host jobs: a registered job reports its settlement back to the
|
|
21
|
+
* owning agent, which would put an unasked-for maintenance notice into the transcript and (under the
|
|
22
|
+
* host's default `wakeup` delivery) open a turn of its own. `autoBuild: false` restores the stricter
|
|
23
|
+
* behaviour where nothing is indexed until the caller asks for it.
|
|
22
24
|
*
|
|
23
25
|
* Sessions the host still holds in memory (`ctx.sessionQuery`) are indexed as well, in a second pass
|
|
24
26
|
* after the file-path transaction commits: a conversation that is still running has no log on disk
|
|
@@ -118,13 +120,17 @@ export function apply(ctx, config) {
|
|
|
118
120
|
// said is findable, and "once until restart" stopped being enough the moment the desktop stayed up
|
|
119
121
|
// for days. The window still absorbs a burst of session creations into one run.
|
|
120
122
|
const autoIndexRuns = new Map();
|
|
123
|
+
// Roots whose automatic run is still executing. Kept apart from `autoIndexRuns`, which is a time
|
|
124
|
+
// window: a first build can outlive the window, and two runs on one root would only fight over the
|
|
125
|
+
// write lock.
|
|
126
|
+
const autoIndexInFlight = new Set();
|
|
121
127
|
// `agent/created` is typed by the host's agent service; this package reads only the two fields it
|
|
122
128
|
// needs through a structural face rather than depending on that package.
|
|
123
129
|
const agentEvents = ctx;
|
|
124
130
|
ctx.effect(function* () {
|
|
125
131
|
if (resolved.autoIndex) {
|
|
126
132
|
yield agentEvents.on('agent/created', payload => {
|
|
127
|
-
scheduleAutoIndex(
|
|
133
|
+
scheduleAutoIndex(resolved, autoIndexRuns, autoIndexInFlight, payload);
|
|
128
134
|
});
|
|
129
135
|
}
|
|
130
136
|
yield ctx.sessiongraph.registerIndexer(indexer);
|
|
@@ -172,13 +178,22 @@ export function isBackgroundIndexReport(report) {
|
|
|
172
178
|
*
|
|
173
179
|
* Runs synchronously inside `agent/created` dispatch, which happens during agent registration, so it
|
|
174
180
|
* must never block or throw: a synchronous index here would hold up the session's own creation. It
|
|
175
|
-
* only decides whether a refresh is warranted and
|
|
176
|
-
*
|
|
181
|
+
* only decides whether a refresh is warranted and starts one in the background.
|
|
182
|
+
*
|
|
183
|
+
* The run deliberately does **not** go through the host's job registry. A registered job announces
|
|
184
|
+
* its settlement to the owning agent — the host injects a completion notice into the next step and,
|
|
185
|
+
* under the default `wakeup` delivery, opens a turn on an idle one. A maintenance refresh nobody
|
|
186
|
+
* asked for must not appear in the transcript or start a reply of its own, so this runs as a plain
|
|
187
|
+
* background promise: the index still keeps itself fresh, and the conversation stays quiet. The
|
|
188
|
+
* explicit `sessiongraph_index` path is the one that still registers a job, because there a caller
|
|
189
|
+
* is waiting for the id.
|
|
177
190
|
* @param config - the resolved plugin configuration.
|
|
178
191
|
* @param autoIndexRuns - when each root last had an automatic refresh, in epoch milliseconds.
|
|
192
|
+
* @param autoIndexInFlight - roots with a background run still executing, so a slow first build cannot
|
|
193
|
+
* be started twice by sessions that open past the time window.
|
|
179
194
|
* @param payload - the `agent/created` dispatch payload.
|
|
180
195
|
*/
|
|
181
|
-
function scheduleAutoIndex(
|
|
196
|
+
function scheduleAutoIndex(config, autoIndexRuns, autoIndexInFlight, payload) {
|
|
182
197
|
try {
|
|
183
198
|
const agent = payload.agent;
|
|
184
199
|
const workspace = agent?.session?.header?.cwd;
|
|
@@ -193,29 +208,20 @@ function scheduleAutoIndex(ctx, config, autoIndexRuns, payload) {
|
|
|
193
208
|
const previous = autoIndexRuns.get(indexRoot);
|
|
194
209
|
if (previous !== undefined && now - previous < config.autoIndexMinIntervalMs)
|
|
195
210
|
return;
|
|
211
|
+
// A run already executing for this root is the one the window would have deduplicated if it had
|
|
212
|
+
// been slow enough to straddle it; starting a second would only collide on the index write lock.
|
|
213
|
+
if (autoIndexInFlight.has(indexRoot))
|
|
214
|
+
return;
|
|
196
215
|
// A first build reads every log on the machine and can take a while, so it stays a background
|
|
197
|
-
//
|
|
216
|
+
// run like the incremental refresh. `autoBuild: false` restores the stricter behaviour where
|
|
198
217
|
// nothing becomes searchable until someone asks for it.
|
|
199
218
|
const existing = hasExistingIndex(indexRoot);
|
|
200
219
|
if (!existing && !config.autoBuild)
|
|
201
220
|
return;
|
|
202
|
-
// `ctx.get` rather than an `inject` entry: background jobs are a host composition choice, and
|
|
203
|
-
// requiring the service would hide this whole indexer from a profile that runs none.
|
|
204
|
-
const jobs = ctx.get('jobs');
|
|
205
|
-
if (jobs === undefined)
|
|
206
|
-
return;
|
|
207
|
-
jobs.start({
|
|
208
|
-
// The registry keys a job by its owning session id, not the agent object.
|
|
209
|
-
owner: agent.id,
|
|
210
|
-
kind: AUTO_INDEX_JOB_KIND,
|
|
211
|
-
label: existing
|
|
212
|
-
? `sessiongraph refresh for ${workspace}`
|
|
213
|
-
: `sessiongraph first build for ${workspace}`,
|
|
214
|
-
run: handle => runIndexJob(indexRoot, {}, config, handle),
|
|
215
|
-
});
|
|
216
|
-
// Marked only after the registry accepted the job, so a refusal leaves the root eligible for
|
|
217
|
-
// the next session that opens.
|
|
218
221
|
autoIndexRuns.set(indexRoot, now);
|
|
222
|
+
autoIndexInFlight.add(indexRoot);
|
|
223
|
+
// Never rejects: a lost refresh is a degradation, not an error the session can act on.
|
|
224
|
+
void runAutomaticIndex(indexRoot, config).finally(() => autoIndexInFlight.delete(indexRoot));
|
|
219
225
|
}
|
|
220
226
|
catch (error) {
|
|
221
227
|
// A throwing listener would veto publication of the agent. Losing a refresh is a degradation,
|
|
@@ -223,6 +229,22 @@ function scheduleAutoIndex(ctx, config, autoIndexRuns, payload) {
|
|
|
223
229
|
console.error(`sessiongraph-sessions: automatic index after session creation failed: ${describeError(error)}`);
|
|
224
230
|
}
|
|
225
231
|
}
|
|
232
|
+
/**
|
|
233
|
+
* Run one automatic refresh to completion, reporting a failure instead of propagating it.
|
|
234
|
+
*
|
|
235
|
+
* The run gets no abort signal of its own: nothing in the transcript can cancel it, and the write
|
|
236
|
+
* lock makes an abandoned or duplicated run harmless. Session creation never waits on this promise.
|
|
237
|
+
* @param indexRoot - the index to refresh.
|
|
238
|
+
* @param config - the resolved plugin configuration.
|
|
239
|
+
*/
|
|
240
|
+
async function runAutomaticIndex(indexRoot, config) {
|
|
241
|
+
try {
|
|
242
|
+
await runIndex(indexRoot, {}, undefined, config);
|
|
243
|
+
}
|
|
244
|
+
catch (error) {
|
|
245
|
+
console.error(`sessiongraph-sessions: automatic index for ${indexRoot} failed: ${describeError(error)}`);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
226
248
|
/**
|
|
227
249
|
* Hand one explicit index run to the host's background-job registry, when the run is large enough to
|
|
228
250
|
* outlive a tool call.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-plugin-sessiongraph-sessions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.20",
|
|
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-
|
|
53
|
-
"dsh-plugin-sessiongraph-
|
|
52
|
+
"dsh-plugin-sessiongraph-service": "^0.1.20",
|
|
53
|
+
"dsh-plugin-sessiongraph-native": "^0.1.20"
|
|
54
54
|
},
|
|
55
55
|
"peerDependencies": {
|
|
56
56
|
"@deepseek-ai/cordis": ">=4.0.1",
|