@huanlin/dsh-plugin-ya-workspace-sidebar 0.3.0 → 0.3.1

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.js CHANGED
@@ -1,7 +1,76 @@
1
+ import { readFileSync, writeFileSync } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import { join } from "node:path";
1
4
  //#region src/index.ts
2
- /** Host half for the browser-only ya-workspace-sidebar plugin. */
5
+ /**
6
+ * Host half for the browser-only ya-workspace-sidebar plugin.
7
+ *
8
+ * The projection cache's write-behind is broken: `cache.write(session)`
9
+ * calls `sessionProjections.checkpoint(session)` which can return
10
+ * non-JSON-serializable values (live LLM state) during a turn, causing
11
+ * `put()` to throw `TypeError: projection checkpoint is not losslessly
12
+ * JSON-serializable`. Both the `turn/end` mandatory write and the throttle
13
+ * writes fail silently (fail-soft), so titles are never durably checkpointed
14
+ * and are lost on host restart.
15
+ *
16
+ * This listener works around the host bug by writing a title-only row
17
+ * directly to the cache file when a `session/title` event lands. The row
18
+ * format matches what `cachedSnapshot` reads: `{ identity, rows: { title } }`.
19
+ * The write is debounced and fail-soft to avoid blocking the event loop or
20
+ * corrupting the file on concurrent writes.
21
+ */
3
22
  const name = "ya-workspace-sidebar";
4
- /** Install the browser-only plugin's empty host half. */
5
- function apply() {}
23
+ const CACHE_PATH = join(homedir(), ".dsh", "storages", "session_projcache.json");
24
+ function apply(ctx) {
25
+ let pending = /* @__PURE__ */ new Map();
26
+ let timer;
27
+ function flush() {
28
+ timer = void 0;
29
+ const batch = pending;
30
+ pending = /* @__PURE__ */ new Map();
31
+ if (batch.size === 0) return;
32
+ try {
33
+ const cache = JSON.parse(readFileSync(CACHE_PATH, "utf8"));
34
+ const sessions = cache.tables?.sessions ?? {};
35
+ for (const [id, payload] of batch) {
36
+ const identity = { createdAt: payload.createdAt };
37
+ if (payload.cwd !== void 0) identity.cwd = payload.cwd;
38
+ const existing = sessions[id];
39
+ if (existing === void 0) sessions[id] = {
40
+ identity,
41
+ rows: { title: {
42
+ ver: 1,
43
+ seq: payload.seq,
44
+ val: payload.title
45
+ } }
46
+ };
47
+ else {
48
+ existing.identity = identity;
49
+ if (existing.rows === void 0) existing.rows = {};
50
+ if (existing.rows.title === void 0 || existing.rows.title.seq <= payload.seq) existing.rows.title = {
51
+ ver: 1,
52
+ seq: payload.seq,
53
+ val: payload.title
54
+ };
55
+ }
56
+ }
57
+ cache.tables.sessions = sessions;
58
+ writeFileSync(CACHE_PATH, JSON.stringify(cache, null, 2) + "\n", "utf8");
59
+ } catch (error) {
60
+ ctx.logger.warn(`ya-workspace-sidebar: title cache flush failed: ${String(error)}`);
61
+ }
62
+ }
63
+ ctx.events.on("session/event", (session, event) => {
64
+ if (event.type !== "session/title") return;
65
+ if (event.data?.title === void 0) return;
66
+ pending.set(session.id, {
67
+ seq: event.seq,
68
+ title: event.data.title,
69
+ createdAt: session.header.createdAt,
70
+ cwd: session.header.cwd
71
+ });
72
+ if (timer === void 0) timer = setTimeout(flush, 2e3);
73
+ });
74
+ }
6
75
  //#endregion
7
76
  export { apply, name };
@@ -1,4 +1,3 @@
1
- /** Host half for the browser-only ya-workspace-sidebar plugin. */
1
+ import type { Context } from 'cordis';
2
2
  export declare const name = "ya-workspace-sidebar";
3
- /** Install the browser-only plugin's empty host half. */
4
- export declare function apply(): void;
3
+ export declare function apply(ctx: Context): void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@huanlin/dsh-plugin-ya-workspace-sidebar",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },