@heixui/dsh-session-suite 0.6.0 → 0.6.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/index.js CHANGED
@@ -28,24 +28,14 @@ import { stripStepTagsFromStream } from './lib/step-tag-filter.js'
28
28
  export const name = 'session-suite'
29
29
 
30
30
  /**
31
- * `agents` is required for implicit memory extraction.
31
+ * The HTTP carrier is the only hard requirement; everything else degrades gracefully.
32
32
  *
33
- * Cordis dispatch is scope-filtered: "agent-scoped listeners receive only events from
34
- * sessions entered through that agent's context". A listener on the plugin's ROOT
35
- * context therefore never sees an agent's session events — which is why our
36
- * `session/event` handler was registered successfully, never fired, and left the pending
37
- * queue empty for six rounds of fixes.
38
- *
39
- * dsh-fish-memory (16k downloads) solves the same problem by injecting `agents`, taking
40
- * one with `ctx.agents.get(sid)`, and listening on `agent.ctx` — the agent's own context.
41
- * Its source records the trap in a comment: the Cordis events that exist are
42
- * `agent/inbox/inserted` and `agent/turn-stopping`, NOT `user/message` /
43
- * `assistant/message` (those are SessionEvent types carried by `session/event`).
44
- *
45
- * Everything else stays optional: the HTTP carrier is still the only hard requirement,
46
- * and a Host without `agents` degrades to no implicit extraction rather than failing.
33
+ * 0.6.2: `agents` and `timer` were added for an implicit-extraction polling loop. That
34
+ * loop crashed the Host with `cannot get property "timer" without inject` on every
35
+ * 500ms tick. Both are removed. Do not re-add them without also proving the tick body
36
+ * cannot throw and that the timer is disposed with the effect.
47
37
  */
48
- export const inject = ['connection', 'agents']
38
+ export const inject = ['connection']
49
39
 
50
40
  /**
51
41
  * @param {any} ctx plugin context
@@ -261,66 +261,20 @@ export function installMemory({ ctx, root, config, log }) {
261
261
  ),
262
262
  )
263
263
 
264
- // --- 2b. Per-agent extraction trigger -----------------------------------
264
+ // --- 2b. Per-agent extraction trigger: REMOVED (0.6.2) -----------------
265
265
  //
266
- // This is the trigger that actually works, copied from how dsh-fish-memory does it
267
- // (16k downloads, demonstrably working). Two things had to be true and neither was:
266
+ // The 500ms agent-poll was the source of a Host crash: its timer callback
267
+ // called `ctx.interval` / `ctx.get("timer")` on a context that had not
268
+ // injected timer, producing `TypeError: cannot get property "timer" without
269
+ // inject` on EVERY tick until the Host died. The WorkBuddy transcript showed
270
+ // `at mount, _onTimeout, listOnTimeout` from our bundle.
268
271
  //
269
- // 1. the listener must be registered on the AGENT's context, not the plugin root.
270
- // Cordis dispatch is scope-filtered, so a root-context `session/event` listener
271
- // receives nothing from an agent's session — which is exactly what we observed:
272
- // registered successfully, `lastExtraction` stayed null forever.
273
- // 2. `agent/turn-stopping` is the hook that fires at the end of a turn on that
274
- // scope. `user/message` and `assistant/message` are SessionEvent TYPES carried
275
- // by `session/event`, not Cordis events — a trap fish-memory documents in a
276
- // comment after hitting it themselves.
277
- //
278
- // The agent is reached through `ctx.agents`, so this requires the `agents` service;
279
- // index.js now injects it. Without it the feature degrades to off rather than throwing.
280
- safe('per-agent extraction hook', () => {
281
- const agents = ctx.get?.('agents')
282
- if (!agents) return
283
-
284
- /** @param {any} agent live agent @returns {void} */
285
- const mountFor = agent => {
286
- const agentCtx = agent?.ctx
287
- if (!agentCtx || typeof agentCtx.on !== 'function') return
288
- // One listener per agent; the context disposes it with the agent.
289
- agentCtx.on('agent/turn-stopping', () => {
290
- const sessionId = agent?.sessionId
291
- if (typeof sessionId !== 'string' || !sessionId) return
292
- // The model choice lives in settings.json, not in the patch config.
293
- void engine
294
- .settings()
295
- .then(settings => {
296
- const chosen = settings?.implicitModel ?? config?.implicitModel
297
- if (!chosen || chosen === 'off') return undefined
298
- const cwd = resolveCwd(ctx, agent)
299
- return extractAfterTurn({ ctx, engine, sessionId, cwd, log, config })
300
- })
301
- .finally(() => publishExtractionTrace(engine))
302
- .catch(error => {
303
- extractionTrace.stage = 'threw'
304
- extractionTrace.reason = errorMessage(error)
305
- publishExtractionTrace(engine)
306
- log('implicit memory extraction failed', error)
307
- })
308
- })
309
- }
310
-
311
- // Mount for agents that already exist, and for every one created later.
312
- for (const agent of agents.list?.() ?? []) mountFor(agent)
313
- if (typeof ctx.on === 'function') {
314
- ctx.on('agent/created', payload => {
315
- try {
316
- mountFor(payload?.agent ?? payload)
317
- } catch {
318
- /* one bad agent must not stop the rest */
319
- }
320
- })
321
- }
322
- })
323
-
272
+ // A recurring timer that can throw on every tick is not an acceptable design
273
+ // for a plugin that runs inside a shared Host process. This whole trigger is
274
+ // removed, and `agents`/`timer` are dropped from inject. Implicit extraction
275
+ // stays off until a trigger can be proven safe. Do not re-add a polling loop
276
+ // without (1) injecting timer, (2) wrapping the tick body in try/catch, and
277
+ // (3) clearing the timer on dispose.
324
278
  // --- 3. Implicit extraction after a turn --------------------------------
325
279
  safe('implicit extraction', () => {
326
280
  // A startup marker, recorded before the listener is even registered.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@heixui/dsh-session-suite",
3
- "version": "0.6.0",
3
+ "version": "0.6.2",
4
4
  "description": "Session checkpoints for DSH: rewind a conversation with its files and memory, permanent session deletion, and shareable exports",
5
5
  "type": "module",
6
6
  "main": "./index.js",