dsh-context-fold 0.1.1 → 0.1.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/lib/client.js CHANGED
@@ -12,16 +12,31 @@ const zh = { "tab.contextFold": "上下文折叠" };
12
12
  /** Dictionary: keep keys aligned with `locale/*.json`. */
13
13
  const en = { "tab.contextFold": "Context fold" };
14
14
  const react = require("react");
15
- /** Fetch the report for one session. */
15
+ /**
16
+ * Fetch the report for one session.
17
+ *
18
+ * Failures are reported rather than swallowed: before the routes existed the
19
+ * tab rendered "no report available", which reads like "this session folded
20
+ * nothing" instead of "the request never landed".
21
+ *
22
+ * @param sessionId - session to report on.
23
+ * @returns the payload, or a message describing why there is none.
24
+ */
16
25
  async function fetchReport(sessionId) {
17
- const response = await fetch("/api/context-fold/report", {
18
- method: "POST",
19
- headers: { "content-type": "application/json" },
20
- body: JSON.stringify({ sessionId })
21
- });
22
- if (!response.ok) return void 0;
23
- const body = await response.json();
24
- return body.ok === true ? body.value : void 0;
26
+ let response;
27
+ try {
28
+ response = await fetch("/api/context-fold/report", {
29
+ method: "POST",
30
+ headers: { "content-type": "application/json" },
31
+ body: JSON.stringify({ sessionId })
32
+ });
33
+ } catch (error) {
34
+ return { error: `request failed: ${error instanceof Error ? error.message : String(error)}` };
35
+ }
36
+ const body = await response.json().catch(() => void 0);
37
+ if (!response.ok) return { error: body?.error ?? `HTTP ${String(response.status)}` };
38
+ if (body?.ok !== true || body.value === void 0) return { error: body?.error ?? "the server returned no value" };
39
+ return { report: body.value };
25
40
  }
26
41
  /** Fetch the full text behind one fold. */
27
42
  async function fetchOriginal(sessionId, locator) {
@@ -83,6 +98,10 @@ const styles = {
83
98
  marginTop: "6px",
84
99
  color: "#facc15"
85
100
  },
101
+ error: {
102
+ marginTop: "6px",
103
+ color: "#f87171"
104
+ },
86
105
  reread: {
87
106
  marginTop: "6px",
88
107
  color: "#f87171"
@@ -231,11 +250,14 @@ function ContextFoldTab(props) {
231
250
  }
232
251
  let cancelled = false;
233
252
  setState({ status: "loading" });
234
- fetchReport(sessionId).then((report) => {
253
+ fetchReport(sessionId).then((result) => {
235
254
  if (cancelled) return;
236
- setState(report === void 0 ? { status: "empty" } : {
255
+ setState("report" in result ? {
237
256
  status: "ready",
238
- report
257
+ report: result.report
258
+ } : {
259
+ status: "error",
260
+ error: result.error
239
261
  });
240
262
  });
241
263
  return () => {
@@ -254,10 +276,14 @@ function ContextFoldTab(props) {
254
276
  style: styles.muted,
255
277
  key: "m"
256
278
  }, "Loading…"));
279
+ else if (state.status === "error") children.push(react.createElement("div", {
280
+ style: styles.error,
281
+ key: "e"
282
+ }, `Could not load the report: ${state.error ?? "unknown"}`));
257
283
  else if (state.status !== "ready" || state.report === void 0) children.push(react.createElement("div", {
258
284
  style: styles.muted,
259
285
  key: "m"
260
- }, "No report available for this session."));
286
+ }, "This session has no folds to report."));
261
287
  else {
262
288
  children.push(react.createElement(Summary, {
263
289
  key: "summary",
package/lib/index.js CHANGED
@@ -1525,11 +1525,12 @@ function json(value, status = 200) {
1525
1525
  /**
1526
1526
  * Register the two read-only routes the tab uses.
1527
1527
  *
1528
- * @param register - the host route registrar.
1528
+ * @param connection - the host `connection` service (its `fetch.register` is the route registrar).
1529
1529
  * @param deps - session and spill access.
1530
1530
  * @returns a disposer for both routes.
1531
1531
  */
1532
- function registerRoutes(register, deps) {
1532
+ function registerRoutes(connection, deps) {
1533
+ const register = connection.fetch.register.bind(connection.fetch);
1533
1534
  const report = register({
1534
1535
  path: "/api/context-fold/report",
1535
1536
  methods: ["POST"],
@@ -1720,18 +1721,18 @@ function apply(ctx, rawConfig = {}) {
1720
1721
  });
1721
1722
  ctx.inject(["connection"], (scope) => {
1722
1723
  const connection = scope.connection;
1723
- if (connection === void 0) {
1724
- ctx.logger.warn("context-fold: no ctx.connection service; the conversation tab has no data source");
1724
+ if (connection === void 0 || typeof connection.fetch?.register !== "function") {
1725
+ ctx.logger.warn("context-fold: no ctx.connection.fetch.register; the conversation tab has no data source");
1725
1726
  return;
1726
1727
  }
1727
1728
  const tokenMeter = ctx.get("tokenMeter");
1728
- registerRoutes(connection, {
1729
+ ctx.effect(() => registerRoutes(connection, {
1729
1730
  sessionOf: (id) => {
1730
1731
  return ctx.get("sessions")?.get(id);
1731
1732
  },
1732
1733
  estimateMessage: (message) => tokenMeter === void 0 ? 0 : tokenMeter.estimateMessage(message),
1733
1734
  ...ctx.get("spillStore") === void 0 ? {} : { spillStore: ctx.get("spillStore") }
1734
- });
1735
+ }), "context-fold: conversation tab routes");
1735
1736
  });
1736
1737
  ctx.on("session/disposed", (session) => {
1737
1738
  states.delete(session.header.id);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-context-fold",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "dsh-context-fold: stage-boundary folding of completed tool results into a conclusion plus a spill path, deterministic and replay-safe.",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",