@lemoncat7/dsh-knowledge 2.5.1 → 2.6.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.
Files changed (47) hide show
  1. package/README.md +15 -3
  2. package/docs/architecture.md +14 -4
  3. package/docs/releases/2.6.0.md +20 -0
  4. package/lib/api.d.ts.map +1 -1
  5. package/lib/api.js +19 -3
  6. package/lib/api.js.map +1 -1
  7. package/lib/client.d.ts.map +1 -1
  8. package/lib/client.js +118 -57
  9. package/lib/client.js.map +4 -4
  10. package/lib/config.d.ts +1 -0
  11. package/lib/config.d.ts.map +1 -1
  12. package/lib/config.js +5 -0
  13. package/lib/config.js.map +1 -1
  14. package/lib/extraction.d.ts +25 -1
  15. package/lib/extraction.d.ts.map +1 -1
  16. package/lib/extraction.js +70 -47
  17. package/lib/extraction.js.map +1 -1
  18. package/lib/index.d.ts.map +1 -1
  19. package/lib/index.js +55 -64
  20. package/lib/index.js.map +1 -1
  21. package/lib/local-provider.d.ts +3 -0
  22. package/lib/local-provider.d.ts.map +1 -1
  23. package/lib/local-provider.js +27 -6
  24. package/lib/local-provider.js.map +1 -1
  25. package/lib/notes/share-import.d.ts +2 -0
  26. package/lib/notes/share-import.d.ts.map +1 -1
  27. package/lib/notes/share-import.js +40 -5
  28. package/lib/notes/share-import.js.map +1 -1
  29. package/lib/provider.d.ts +3 -0
  30. package/lib/provider.d.ts.map +1 -1
  31. package/lib/remote-provider.d.ts +3 -0
  32. package/lib/remote-provider.d.ts.map +1 -1
  33. package/lib/remote-provider.js +10 -0
  34. package/lib/remote-provider.js.map +1 -1
  35. package/lib/writeback/queue.d.ts +40 -0
  36. package/lib/writeback/queue.d.ts.map +1 -0
  37. package/lib/writeback/queue.js +193 -0
  38. package/lib/writeback/queue.js.map +1 -0
  39. package/lib/writeback/status-client.d.ts +22 -0
  40. package/lib/writeback/status-client.d.ts.map +1 -0
  41. package/lib/writeback/status-client.js +97 -0
  42. package/lib/writeback/status-client.js.map +1 -0
  43. package/package.json +1 -1
  44. package/web/api-client.js +2 -1
  45. package/web/app.js +30 -12
  46. package/web/styles.css +4 -8
  47. package/web/ui-primitives.js +1 -0
package/lib/client.js CHANGED
@@ -27,6 +27,87 @@ __export(client_exports, {
27
27
  module.exports = __toCommonJS(client_exports);
28
28
  var import_react4 = require("react");
29
29
 
30
+ // src/writeback/status-client.ts
31
+ var WritebackStatusClient = class {
32
+ // Browser fetch checks its Window receiver. Never store it as an unbound
33
+ // instance method: this.fetcher() would supply the client as its receiver.
34
+ constructor(url, change, fetcher = (...args) => globalThis.fetch(...args)) {
35
+ this.url = url;
36
+ this.change = change;
37
+ this.fetcher = fetcher;
38
+ }
39
+ request;
40
+ timer;
41
+ disposed = false;
42
+ visible = true;
43
+ retrying = false;
44
+ failures = 0;
45
+ value;
46
+ readError;
47
+ setVisible(visible) {
48
+ this.visible = visible;
49
+ if (visible) this.refresh();
50
+ else {
51
+ clearTimeout(this.timer);
52
+ if (!this.retrying) this.request?.abort();
53
+ }
54
+ }
55
+ refresh() {
56
+ if (this.disposed || !this.visible || this.retrying || this.request && !this.request.signal.aborted) return;
57
+ void this.load(false);
58
+ }
59
+ retry() {
60
+ if (this.disposed || this.retrying || !this.value?.retryable) return;
61
+ this.retrying = true;
62
+ this.request?.abort();
63
+ this.change(this.value, true);
64
+ void this.load(true);
65
+ }
66
+ async load(retry) {
67
+ clearTimeout(this.timer);
68
+ const controller = new AbortController();
69
+ this.request = controller;
70
+ const timeout = setTimeout(() => controller.abort(new Error("\u72B6\u6001\u8BF7\u6C42\u8D85\u65F6")), 15e3);
71
+ let delay = 15e3;
72
+ try {
73
+ const response = await this.fetcher(this.url, {
74
+ method: retry ? "POST" : "GET",
75
+ signal: controller.signal,
76
+ headers: { accept: "application/json", "x-dsh-knowledge-client": "conversation-web" }
77
+ });
78
+ const body = await response.json();
79
+ if (this.request !== controller || this.disposed) return;
80
+ if (!response.ok && (retry || response.status !== 404)) throw new Error(body.error ?? `\u72B6\u6001\u8BF7\u6C42\u5931\u8D25\uFF08HTTP ${response.status}\uFF09`);
81
+ this.readError = void 0;
82
+ if (response.ok && body.summary) {
83
+ this.value = body;
84
+ this.failures = 0;
85
+ delay = body.status === "completed" ? 0 : body.status === "failed" ? 15e3 : 1500;
86
+ } else {
87
+ delay = ++this.failures <= 3 ? 1500 : 6e4;
88
+ }
89
+ } catch (error) {
90
+ if (this.request !== controller || this.disposed) return;
91
+ delay = Math.min(6e4, 2e3 * 2 ** Math.min(5, this.failures++));
92
+ if (retry && this.value) this.value = { ...this.value, error: error instanceof Error ? error.message : String(error) };
93
+ else if (this.visible) this.readError = "\u6682\u65F6\u65E0\u6CD5\u8BFB\u53D6\u56DE\u5199\u72B6\u6001\uFF0C\u6B63\u5728\u81EA\u52A8\u91CD\u8BD5\uFF1B\u8FD9\u4E0D\u4EE3\u8868\u56DE\u5199\u5931\u8D25\u3002";
94
+ } finally {
95
+ clearTimeout(timeout);
96
+ if (this.request === controller && !this.disposed) {
97
+ this.request = void 0;
98
+ if (retry) this.retrying = false;
99
+ this.change(this.value, this.retrying, this.readError);
100
+ if (delay && this.visible) this.timer = setTimeout(() => this.refresh(), delay);
101
+ }
102
+ }
103
+ }
104
+ dispose() {
105
+ this.disposed = true;
106
+ clearTimeout(this.timer);
107
+ this.request?.abort();
108
+ }
109
+ };
110
+
30
111
  // src/workspace-ownership.ts
31
112
  var WORKSPACE_ACTIVATE_EVENT = "@lemoncat7/dsh-plugin-ui/workspace-activate";
32
113
  function activatePluginWorkspace(pluginId) {
@@ -3943,69 +4024,48 @@ function KnowledgeWritebackStatus({
3943
4024
  }) {
3944
4025
  const [state, setState] = (0, import_react4.useState)();
3945
4026
  const [retrying, setRetrying] = (0, import_react4.useState)(false);
4027
+ const [readError, setReadError] = (0, import_react4.useState)();
4028
+ const client = (0, import_react4.useRef)();
4029
+ const container = (0, import_react4.useRef)(null);
3946
4030
  (0, import_react4.useEffect)(() => {
3947
- const controller = new AbortController();
3948
- let timer;
3949
- let missingAttempts = 0;
3950
- const schedule = (delay) => {
3951
- if (!controller.signal.aborted) timer = setTimeout(() => {
3952
- void load();
3953
- }, delay);
3954
- };
3955
- const load = async () => {
3956
- try {
3957
- const response = await fetch(`/knowledge-control/v1/writeback-status?sessionId=${encodeURIComponent(sessionId)}&turn=${turn}`, {
3958
- headers: { accept: "application/json", "x-dsh-knowledge-client": "conversation-web" },
3959
- signal: controller.signal
3960
- });
3961
- if (response.ok) {
3962
- const value = await response.json();
3963
- if (value.summary) setState(value);
3964
- if (value.status === "running") schedule(1500);
3965
- return;
3966
- }
3967
- if (response.status === 404 && missingAttempts < 3) {
3968
- missingAttempts += 1;
3969
- schedule(1500);
3970
- }
3971
- } catch {
3972
- if (!controller.signal.aborted && missingAttempts < 3) {
3973
- missingAttempts += 1;
3974
- schedule(2e3);
3975
- }
4031
+ setState(void 0);
4032
+ setRetrying(false);
4033
+ setReadError(void 0);
4034
+ const status = new WritebackStatusClient(
4035
+ `/knowledge-control/v1/writeback-status?sessionId=${encodeURIComponent(sessionId)}&turn=${turn}`,
4036
+ (value, pending, error) => {
4037
+ setState(value);
4038
+ setRetrying(pending);
4039
+ setReadError(error);
3976
4040
  }
3977
- };
3978
- void load();
4041
+ );
4042
+ client.current = status;
4043
+ let inView = true;
4044
+ const refresh = () => status.setVisible(inView && !document.hidden);
4045
+ const observer = typeof IntersectionObserver === "undefined" ? void 0 : new IntersectionObserver((entries2) => {
4046
+ inView = entries2[0]?.isIntersecting ?? true;
4047
+ refresh();
4048
+ }, { rootMargin: "100px" });
4049
+ if (container.current) observer?.observe(container.current);
4050
+ document.addEventListener("visibilitychange", refresh);
4051
+ window.addEventListener("focus", refresh);
4052
+ window.addEventListener("online", refresh);
4053
+ refresh();
3979
4054
  return () => {
3980
- controller.abort();
3981
- if (timer !== void 0) clearTimeout(timer);
4055
+ observer?.disconnect();
4056
+ document.removeEventListener("visibilitychange", refresh);
4057
+ window.removeEventListener("focus", refresh);
4058
+ window.removeEventListener("online", refresh);
4059
+ status.dispose();
4060
+ client.current = void 0;
3982
4061
  };
3983
4062
  }, [sessionId, turn]);
3984
- if (state === void 0) return null;
3985
- const retry = async () => {
3986
- setRetrying(true);
3987
- try {
3988
- const response = await fetch(`/knowledge-control/v1/writeback-status?sessionId=${encodeURIComponent(sessionId)}&turn=${turn}`, {
3989
- method: "POST",
3990
- headers: { accept: "application/json", "x-dsh-knowledge-client": "conversation-web" }
3991
- });
3992
- const body = await response.json().catch(() => ({}));
3993
- if (!response.ok) throw new Error(body.error ?? `retry failed with HTTP ${response.status}`);
3994
- setState(body);
3995
- } catch (error) {
3996
- setState((previous) => previous === void 0 ? previous : {
3997
- ...previous,
3998
- error: error instanceof Error ? error.message : String(error),
3999
- retryable: true
4000
- });
4001
- } finally {
4002
- setRetrying(false);
4003
- }
4004
- };
4063
+ if (state === void 0) return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { ref: container, children: readError && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "dsh-knowledge-writeback-notice", role: "status", children: readError }) });
4064
+ const retry = () => client.current?.retry();
4005
4065
  const destinations = state.destinations ?? [];
4006
4066
  const summary = state.summary.replace(/^知识库回写\s*·\s*/u, "");
4007
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "dsh-knowledge-writeback-notice", "data-status": state.status, children: [
4008
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "dsh-knowledge-writeback-summary", role: state.status === "running" ? "status" : void 0, "aria-atomic": "true", children: [
4067
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { ref: container, className: "dsh-knowledge-writeback-notice", "data-status": state.status, children: [
4068
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "dsh-knowledge-writeback-summary", role: "status", "aria-atomic": "true", children: [
4009
4069
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "\u77E5\u8BC6\u5E93\u56DE\u5199" }),
4010
4070
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("strong", { children: "@lemoncat7/dsh-knowledge" }),
4011
4071
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { title: state.error, children: summary }),
@@ -4031,7 +4091,8 @@ function KnowledgeWritebackStatus({
4031
4091
  ) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("strong", { title: destination.documentTitle, children: `\u62DF\u65B0\u5EFA\uFF1A${destination.documentTitle}` }),
4032
4092
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("small", { "data-disposition": destination.disposition, children: destination.disposition === "written" ? destination.documentState === "resolved" ? "\u5DF2\u89E3\u51B3" : destination.documentState === "complete" ? "\u5DF2\u5B8C\u6210" : "\u5DF2\u5199\u5165" : destination.documentState ? "\u5F85\u5BA1\u6838 \xB7 \u6807\u8BB0" + (destination.documentState === "resolved" ? "\u89E3\u51B3" : "\u5B8C\u6210") : "\u5F85\u5BA1\u6838" })
4033
4093
  ] }, `${destination.knowledgeBaseId}:${destination.documentId ?? destination.documentTitle}:${index}`)) }),
4034
- state.status === "failed" && state.error && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "dsh-knowledge-writeback-error", role: "alert", children: state.error })
4094
+ state.status === "failed" && state.error && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "dsh-knowledge-writeback-error", role: "alert", children: state.error }),
4095
+ readError && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "dsh-knowledge-writeback-error", role: "status", children: readError })
4035
4096
  ] });
4036
4097
  }
4037
4098
  function createKnowledgeWorkspaceController(client, beforeOpen) {