@klarkxy/dsh-self-improvement 0.1.0

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 ADDED
@@ -0,0 +1,1067 @@
1
+ function __createDshNodeShims() {
2
+ class EventEmitter {
3
+ constructor() {
4
+ this._e = Object.create(null)
5
+ }
6
+ on(type, fn) {
7
+ (this._e[type] ||= []).push(fn)
8
+ return this
9
+ }
10
+ addListener(type, fn) {
11
+ return this.on(type, fn)
12
+ }
13
+ once(type, fn) {
14
+ const wrap = (...args) => {
15
+ this.off(type, wrap)
16
+ fn(...args)
17
+ }
18
+ return this.on(type, wrap)
19
+ }
20
+ off(type, fn) {
21
+ const list = this._e[type]
22
+ if (list) this._e[type] = list.filter((item) => item !== fn)
23
+ return this
24
+ }
25
+ removeListener(type, fn) {
26
+ return this.off(type, fn)
27
+ }
28
+ emit(type, ...args) {
29
+ const list = this._e[type]
30
+ if (!list) return false
31
+ for (const fn of list.slice()) fn(...args)
32
+ return true
33
+ }
34
+ removeAllListeners(type) {
35
+ if (type) delete this._e[type]
36
+ else this._e = Object.create(null)
37
+ return this
38
+ }
39
+ listeners(type) {
40
+ return (this._e[type] || []).slice()
41
+ }
42
+ setMaxListeners() {
43
+ return this
44
+ }
45
+ }
46
+
47
+ class Buffer extends Uint8Array {
48
+ static from(value, encodingOrOffset, length) {
49
+ if (typeof value === 'string') return new Buffer(new TextEncoder().encode(value))
50
+ if (value instanceof ArrayBuffer) return new Buffer(new Uint8Array(value, encodingOrOffset, length))
51
+ if (ArrayBuffer.isView(value)) return new Buffer(new Uint8Array(value.buffer, value.byteOffset, value.byteLength))
52
+ if (Array.isArray(value) || value && typeof value.length === 'number') return new Buffer(Uint8Array.from(value))
53
+ return new Buffer(0)
54
+ }
55
+ static alloc(size, fill) {
56
+ const buf = new Buffer(size)
57
+ if (fill !== undefined && fill !== 0) {
58
+ if (typeof fill === 'string') {
59
+ const bytes = new TextEncoder().encode(fill)
60
+ for (let i = 0; i < size; i += 1) buf[i] = bytes[i % bytes.length]
61
+ } else buf.fill(fill)
62
+ }
63
+ return buf
64
+ }
65
+ static allocUnsafe(size) {
66
+ return new Buffer(size)
67
+ }
68
+ static allocUnsafeSlow(size) {
69
+ return new Buffer(size)
70
+ }
71
+ static concat(list, totalLength) {
72
+ const length = totalLength ?? list.reduce((sum, item) => sum + item.length, 0)
73
+ const out = new Buffer(length)
74
+ let offset = 0
75
+ for (const item of list) {
76
+ out.set(item, offset)
77
+ offset += item.length
78
+ }
79
+ return out
80
+ }
81
+ static isBuffer(value) {
82
+ return value instanceof Buffer
83
+ }
84
+ static byteLength(value) {
85
+ if (typeof value === 'string') return new TextEncoder().encode(value).length
86
+ return value?.byteLength ?? value?.length ?? 0
87
+ }
88
+ static isEncoding(encoding) {
89
+ return /^(utf8|utf-8|ascii|latin1|binary|hex|base64|base64url)$/i.test(String(encoding || ''))
90
+ }
91
+ toString(encoding) {
92
+ if (encoding === 'hex') return [...this].map((byte) => byte.toString(16).padStart(2, '0')).join('')
93
+ if (encoding === 'base64') {
94
+ let binary = ''
95
+ this.forEach((byte) => {
96
+ binary += String.fromCharCode(byte)
97
+ })
98
+ return btoa(binary)
99
+ }
100
+ return new TextDecoder().decode(this)
101
+ }
102
+ slice(start, end) {
103
+ return Buffer.from(super.subarray(start, end))
104
+ }
105
+ copy(target, targetStart = 0, start = 0, end = this.length) {
106
+ const sliced = this.subarray(start, end)
107
+ target.set(sliced, targetStart)
108
+ return sliced.length
109
+ }
110
+ write(string, offset = 0) {
111
+ const bytes = new TextEncoder().encode(string)
112
+ const written = Math.min(bytes.length, this.length - offset)
113
+ this.set(bytes.subarray(0, written), offset)
114
+ return written
115
+ }
116
+ }
117
+
118
+ function inherits(ctor, superCtor) {
119
+ ctor.super_ = superCtor
120
+ ctor.prototype = Object.create(superCtor.prototype, {
121
+ constructor: { value: ctor, writable: true, configurable: true },
122
+ })
123
+ }
124
+
125
+ if (!globalThis.Buffer) globalThis.Buffer = Buffer
126
+
127
+ return {
128
+ buffer: { Buffer, SlowBuffer: Buffer, INSPECT_MAX_BYTES: 50, kMaxLength: 0x7fffffff },
129
+ stream: {
130
+ Stream: EventEmitter,
131
+ Readable: EventEmitter,
132
+ Writable: EventEmitter,
133
+ Duplex: EventEmitter,
134
+ Transform: EventEmitter,
135
+ PassThrough: EventEmitter,
136
+ },
137
+ events: { EventEmitter },
138
+ util: {
139
+ deprecate(fn) {
140
+ return fn
141
+ },
142
+ inherits,
143
+ inspect() {
144
+ return ''
145
+ },
146
+ format(value) {
147
+ return String(value)
148
+ },
149
+ types: { isBuffer: Buffer.isBuffer },
150
+ },
151
+ }
152
+ }
153
+
154
+ window.__ModuleLoader__.load({
155
+ id: "@klarkxy/dsh-self-improvement",
156
+ factory: (dshRequire) => {
157
+ var __nodeShims;
158
+ var process = globalThis.process || { env: {}, nextTick: function (fn) { var args = [].slice.call(arguments, 1); queueMicrotask(function () { fn.apply(null, args); }); } };
159
+ var require = function (id) {
160
+ if (id === 'buffer' || id === 'stream' || id === 'util' || id === 'events') {
161
+ if (!__nodeShims) __nodeShims = __createDshNodeShims();
162
+ return __nodeShims[id];
163
+ }
164
+ return dshRequire(id);
165
+ };
166
+ var module = { exports: {} };
167
+ var exports = module.exports;
168
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
169
+ let react = require("react");
170
+ let react_jsx_runtime = require("react/jsx-runtime");
171
+ //#region ../dsh-ai-services/src/client-utils.ts
172
+ /** The Editor retains its manuscript session separately; native DSH exposes the main-view binding. */
173
+ function selectedSessionId(client) {
174
+ return client.uiWorkspace.current ? client.uiWorkspace.current.getSnapshot()?.sessionId ?? "" : client.uiSession.adapter.current.getSnapshot().key ?? "";
175
+ }
176
+ /** Owner props win; native settings only supplies close, so resolve its selected session. */
177
+ function useNativeSeat(client, props) {
178
+ const current = (0, react.useSyncExternalStore)((0, react.useCallback)((fn) => (client.uiWorkspace.current ?? client.uiSession.adapter.current).subscribe(fn), [client]), (0, react.useCallback)(() => selectedSessionId(client), [client]), () => "");
179
+ const language = (0, react.useSyncExternalStore)((0, react.useCallback)((fn) => client.locale.subscribe(fn), [client]), (0, react.useCallback)(() => client.locale.getSnapshot().active, [client]), () => "en");
180
+ const row = props && typeof props === "object" ? props : {};
181
+ const owner = row.owner && typeof row.owner === "object" ? row.owner : {};
182
+ const sessionId = typeof row.sessionId === "string" ? row.sessionId : typeof owner.sessionId === "string" ? owner.sessionId : current;
183
+ const requestedLocale = row.locale ?? owner.locale ?? language;
184
+ return {
185
+ sessionId,
186
+ locale: String(requestedLocale).startsWith("zh") ? "zh" : "en",
187
+ hidden: row.hidden === true || owner.hidden === true
188
+ };
189
+ }
190
+ /** Refresh on native log boundaries/reconnect/focus. Read-only settling is bounded to an observed job. */
191
+ function useFeatureRefresh(client, sessionId, refresh, working = false, enabled = true) {
192
+ const refreshRef = (0, react.useRef)(refresh);
193
+ refreshRef.current = refresh;
194
+ (0, react.useEffect)(() => {
195
+ if (!enabled) return;
196
+ let timer;
197
+ const queue = () => {
198
+ if (typeof document !== "undefined" && document.visibilityState === "hidden") return;
199
+ clearTimeout(timer);
200
+ timer = setTimeout(() => refreshRef.current(), 150);
201
+ };
202
+ const stopEvents = (sessionId ? client.sessions.binding?.(sessionId)?.eventSource : void 0)?.subscribe(queue);
203
+ const stopConnection = client.connection?.generation?.subscribe(queue);
204
+ const visibility = () => {
205
+ if (document.visibilityState === "visible") queue();
206
+ };
207
+ window.addEventListener("focus", queue);
208
+ document.addEventListener("visibilitychange", visibility);
209
+ document.addEventListener("toggle", queue, true);
210
+ return () => {
211
+ clearTimeout(timer);
212
+ stopEvents?.();
213
+ stopConnection?.();
214
+ window.removeEventListener("focus", queue);
215
+ document.removeEventListener("visibilitychange", visibility);
216
+ document.removeEventListener("toggle", queue, true);
217
+ };
218
+ }, [
219
+ client,
220
+ sessionId,
221
+ enabled
222
+ ]);
223
+ (0, react.useEffect)(() => {
224
+ if (!enabled || !working) return;
225
+ let delay = 250;
226
+ const until = Date.now() + 3e5;
227
+ let timer;
228
+ const tick = () => {
229
+ if (Date.now() >= until) return;
230
+ if (document.visibilityState !== "hidden") refreshRef.current();
231
+ delay = Math.min(delay * 2, 2e3);
232
+ timer = setTimeout(tick, delay);
233
+ };
234
+ timer = setTimeout(tick, delay);
235
+ return () => clearTimeout(timer);
236
+ }, [
237
+ client,
238
+ sessionId,
239
+ working,
240
+ enabled
241
+ ]);
242
+ }
243
+ //#endregion
244
+ //#region src/contracts.ts
245
+ const SELF_IMPROVEMENT_RPC_CHANNEL = "/dsh-self-improvement";
246
+ const MEMORY_UNAVAILABLE_MESSAGE = "记忆服务不可用。请先单独启用「记忆」插件;启用自我改进不会自动打开记忆。";
247
+ const MEMORY_UNAVAILABLE_MESSAGE_EN = "Memory is unavailable. Enable the Memory plugin separately; turning on self-improvement does not enable Memory.";
248
+ //#endregion
249
+ //#region src/rpc-result.ts
250
+ function unwrap(result) {
251
+ if (!result.ok) throw new Error(result.error.message);
252
+ return result.value;
253
+ }
254
+ //#endregion
255
+ //#region src/skills.ts
256
+ function downloadMarkdown(filename, markdown, doc = typeof document === "undefined" ? void 0 : document) {
257
+ if (!doc) return false;
258
+ const blob = new Blob([markdown], { type: "text/markdown;charset=utf-8" });
259
+ const url = URL.createObjectURL(blob);
260
+ const anchor = doc.createElement("a");
261
+ anchor.href = url;
262
+ anchor.setAttribute("download", filename);
263
+ anchor.rel = "noopener";
264
+ doc.body.appendChild(anchor);
265
+ anchor.click();
266
+ anchor.remove();
267
+ URL.revokeObjectURL(url);
268
+ return true;
269
+ }
270
+ function exportRevocationCopy(locale) {
271
+ return locale === "en" ? "Export record revoked. Already downloaded files are not recalled." : "已撤回导出记录。不会收回或删除已下载的文件。";
272
+ }
273
+ function skillExportStateLabel(record, locale) {
274
+ if (record.exportState === "recorded") return locale === "en" ? "Download recorded" : "已记录下载";
275
+ if (record.exportState === "revoked") return locale === "en" ? "Download record revoked" : "已撤回下载记录";
276
+ return locale === "en" ? "Not downloaded" : "未下载";
277
+ }
278
+ //#endregion
279
+ //#region src/review-lifetime.ts
280
+ function createReviewGeneration(start = 0) {
281
+ let current = start;
282
+ return {
283
+ current: () => current,
284
+ next: () => {
285
+ current += 1;
286
+ return current;
287
+ },
288
+ isCurrent: (token) => token === current
289
+ };
290
+ }
291
+ function reviewRequestStillCurrent(input) {
292
+ return input.gate.isCurrent(input.token) && !input.signal.aborted && input.sessionId === input.viewSessionId;
293
+ }
294
+ /** Capture session, generation token, and abort lifetime before the first await. */
295
+ function beginReviewRequest(gate, sessionId, previous) {
296
+ previous?.abort();
297
+ const controller = new AbortController();
298
+ return {
299
+ sessionId,
300
+ token: gate.next(),
301
+ signal: controller.signal,
302
+ controller
303
+ };
304
+ }
305
+ function disposeReviewRequest(gate, controller) {
306
+ controller.abort();
307
+ gate.next();
308
+ }
309
+ function shouldSkipReviewRefresh(input) {
310
+ return input.busy || input.editing === true;
311
+ }
312
+ async function loadReviewSnapshot(input) {
313
+ const captured = input.sessionId;
314
+ const raw = await input.rpc("status", { sessionId: captured }, input.signal);
315
+ if (!reviewRequestStillCurrent({
316
+ token: input.token,
317
+ gate: input.gate,
318
+ signal: input.signal,
319
+ sessionId: captured,
320
+ viewSessionId: input.viewSessionId()
321
+ })) return void 0;
322
+ return unwrap(raw);
323
+ }
324
+ /** Read-only status peek; uses an independent signal so it cannot abort an in-flight write. */
325
+ async function peekReviewSnapshot(input) {
326
+ if (shouldSkipReviewRefresh({
327
+ busy: input.busy(),
328
+ editing: input.editing?.() === true
329
+ })) return void 0;
330
+ const token = input.token;
331
+ if (!input.gate.isCurrent(token) || token === 0) return void 0;
332
+ const next = await loadReviewSnapshot({
333
+ rpc: input.rpc,
334
+ sessionId: input.sessionId,
335
+ token,
336
+ gate: input.gate,
337
+ signal: new AbortController().signal,
338
+ viewSessionId: input.viewSessionId
339
+ });
340
+ if (!next) return void 0;
341
+ if (shouldSkipReviewRefresh({
342
+ busy: input.busy(),
343
+ editing: input.editing?.() === true
344
+ })) return void 0;
345
+ return next;
346
+ }
347
+ async function exportSkillIfCurrent(input) {
348
+ const captured = input.sessionId;
349
+ const still = () => reviewRequestStillCurrent({
350
+ token: input.token,
351
+ gate: input.gate,
352
+ signal: input.signal,
353
+ sessionId: captured,
354
+ viewSessionId: input.viewSessionId()
355
+ });
356
+ const prepared = unwrap(await input.rpc("skill.export", {
357
+ id: input.record.id,
358
+ expectedRevision: input.record.revision,
359
+ sessionId: captured
360
+ }, input.signal));
361
+ if (!still()) return "stale";
362
+ const started = (input.download ?? downloadMarkdown)(prepared.filename, prepared.markdown);
363
+ if (!still()) return "stale";
364
+ if (!started) throw new Error("未能开始下载。");
365
+ unwrap(await input.rpc("skill.exported", {
366
+ id: prepared.skill.id,
367
+ expectedRevision: prepared.skill.revision,
368
+ filename: prepared.filename,
369
+ sessionId: captured
370
+ }, input.signal));
371
+ if (!still()) return "stale";
372
+ return "recorded";
373
+ }
374
+ //#endregion
375
+ //#region src/client.tsx
376
+ const name = "dsh-self-improvement-client";
377
+ const inject = [
378
+ "slots",
379
+ "connection",
380
+ "sessions",
381
+ "locale",
382
+ "uiWorkspace",
383
+ "uiSession"
384
+ ];
385
+ function parseSeatProps(props) {
386
+ const row = props && typeof props === "object" ? props : {};
387
+ const nested = row.owner && typeof row.owner === "object" ? row.owner : void 0;
388
+ return {
389
+ sessionId: typeof row.sessionId === "string" && row.sessionId ? row.sessionId : typeof nested?.sessionId === "string" ? nested.sessionId : "",
390
+ locale: row.locale === "en" || nested?.locale === "en" ? "en" : "zh",
391
+ hidden: row.hidden === true || nested?.hidden === true
392
+ };
393
+ }
394
+ function memoryUnavailableCopy(locale) {
395
+ return locale === "en" ? MEMORY_UNAVAILABLE_MESSAGE_EN : MEMORY_UNAVAILABLE_MESSAGE;
396
+ }
397
+ function statusLabel(status, locale) {
398
+ return (locale === "en" ? {
399
+ candidate: "Candidate",
400
+ active: "Active",
401
+ rejected: "Rejected",
402
+ superseded: "Superseded",
403
+ revoked: "Revoked",
404
+ deleted: "Deleted"
405
+ } : {
406
+ candidate: "候选",
407
+ active: "已生效",
408
+ rejected: "已拒绝",
409
+ superseded: "已替代",
410
+ revoked: "已撤回",
411
+ deleted: "已删除"
412
+ })[status];
413
+ }
414
+ const emptySnapshot = () => ({
415
+ memoryAvailable: false,
416
+ memoryMessage: MEMORY_UNAVAILABLE_MESSAGE,
417
+ generation: 0,
418
+ storageFailed: false,
419
+ lessons: [],
420
+ skills: []
421
+ });
422
+ function LessonEvidence({ record, locale }) {
423
+ return record.evidence.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
424
+ className: "si-meta",
425
+ children: locale === "en" ? "No evidence refs." : "没有依据引用。"
426
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
427
+ className: "si-evidence",
428
+ children: record.evidence.map((ref) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", { children: [
429
+ ref.kind,
430
+ " · ",
431
+ ref.sessionId,
432
+ "#",
433
+ ref.seq,
434
+ ref.excerpt ? ` — ${ref.excerpt}` : ""
435
+ ] }, `${ref.sessionId}:${ref.seq}:${ref.kind}`))
436
+ });
437
+ }
438
+ function ConfirmButton(props) {
439
+ const [armed, setArmed] = (0, react.useState)(false);
440
+ const timer = (0, react.useRef)(void 0);
441
+ (0, react.useEffect)(() => () => clearTimeout(timer.current), []);
442
+ function disarm() {
443
+ clearTimeout(timer.current);
444
+ setArmed(false);
445
+ }
446
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
447
+ type: "button",
448
+ className: "si-danger",
449
+ disabled: props.disabled,
450
+ onClick: () => {
451
+ if (!armed) {
452
+ setArmed(true);
453
+ timer.current = setTimeout(() => setArmed(false), 3e3);
454
+ return;
455
+ }
456
+ disarm();
457
+ props.onConfirm();
458
+ },
459
+ onBlur: disarm,
460
+ children: armed ? props.confirmLabel : props.label
461
+ });
462
+ }
463
+ function LessonList(props) {
464
+ const { lessons, locale, busy, projectId, onPromote, onReject, onRevoke } = props;
465
+ if (lessons.length === 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
466
+ className: "si-empty",
467
+ children: locale === "en" ? "No lessons yet." : "还没有教训。"
468
+ });
469
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ol", {
470
+ className: "si-list",
471
+ children: lessons.map((record) => {
472
+ const candidate = record.status === "candidate";
473
+ const active = record.status === "active";
474
+ const foreignProject = record.scope.kind === "project" && Boolean(projectId) && record.scope.projectId !== projectId;
475
+ const scope = record.scope.kind === "global" ? locale === "en" ? "global" : "全局" : record.scope.projectId;
476
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
477
+ className: "si-card",
478
+ "data-status": record.status,
479
+ children: [
480
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: record.title }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
481
+ className: "si-meta",
482
+ children: [
483
+ statusLabel(record.status, locale),
484
+ " · ",
485
+ scope
486
+ ]
487
+ })] }),
488
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: record.content }),
489
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LessonEvidence, {
490
+ record,
491
+ locale
492
+ }),
493
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
494
+ className: "si-actions",
495
+ children: [
496
+ active && record.scope.kind === "project" && !foreignProject ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
497
+ type: "button",
498
+ disabled: busy,
499
+ onClick: () => onPromote(record),
500
+ children: locale === "en" ? "Promote to global" : "提升为全局"
501
+ }) : null,
502
+ candidate ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ConfirmButton, {
503
+ disabled: busy,
504
+ label: locale === "en" ? "Reject" : "拒绝",
505
+ confirmLabel: locale === "en" ? "Confirm reject?" : "确认拒绝?",
506
+ onConfirm: () => onReject(record)
507
+ }) : null,
508
+ active ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ConfirmButton, {
509
+ disabled: busy,
510
+ label: locale === "en" ? "Revoke" : "撤回",
511
+ confirmLabel: locale === "en" ? "Confirm revoke?" : "确认撤回?",
512
+ onConfirm: () => onRevoke(record)
513
+ }) : null,
514
+ foreignProject ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
515
+ className: "si-meta",
516
+ children: locale === "en" ? "Other project — promotion is blocked here." : "其他项目的教训,此处不能提升。"
517
+ }) : null
518
+ ]
519
+ })
520
+ ]
521
+ }, record.id);
522
+ })
523
+ });
524
+ }
525
+ function SkillList(props) {
526
+ const { skills, locale, busy } = props;
527
+ if (skills.length === 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
528
+ className: "si-empty",
529
+ children: locale === "en" ? "No skill drafts." : "没有技能草稿。"
530
+ });
531
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ol", {
532
+ className: "si-list",
533
+ children: skills.map((record) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
534
+ className: "si-card",
535
+ "data-skill-status": record.status,
536
+ "data-export": record.exportState,
537
+ children: [
538
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: record.title }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
539
+ className: "si-meta",
540
+ children: [
541
+ record.status,
542
+ " · ",
543
+ skillExportStateLabel(record, locale)
544
+ ]
545
+ })] }),
546
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
547
+ className: "si-preview",
548
+ children: record.markdown
549
+ }),
550
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
551
+ className: "si-actions",
552
+ children: [
553
+ record.status === "preview" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
554
+ type: "button",
555
+ disabled: busy,
556
+ onClick: () => props.onAccept(record),
557
+ children: locale === "en" ? "Accept draft" : "接受草稿"
558
+ }) : null,
559
+ record.status === "preview" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
560
+ type: "button",
561
+ disabled: busy,
562
+ onClick: () => props.onReject(record),
563
+ children: locale === "en" ? "Reject draft" : "拒绝草稿"
564
+ }) : null,
565
+ record.status === "accepted" || record.status === "preview" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
566
+ type: "button",
567
+ disabled: busy,
568
+ onClick: () => props.onExport(record),
569
+ children: locale === "en" ? "Download Markdown" : "下载 Markdown"
570
+ }) : null,
571
+ record.exportState === "recorded" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ConfirmButton, {
572
+ disabled: busy,
573
+ label: locale === "en" ? "Revoke export record" : "撤回导出记录",
574
+ confirmLabel: locale === "en" ? "Confirm revoke export record?" : "确认撤回导出记录?",
575
+ onConfirm: () => props.onUnexport(record)
576
+ }) : null,
577
+ record.status === "accepted" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ConfirmButton, {
578
+ disabled: busy,
579
+ label: locale === "en" ? "Revoke skill" : "撤回技能",
580
+ confirmLabel: locale === "en" ? "Confirm revoke skill?" : "确认撤回技能?",
581
+ onConfirm: () => props.onRevoke(record)
582
+ }) : null
583
+ ]
584
+ })
585
+ ]
586
+ }, record.id))
587
+ });
588
+ }
589
+ function ReviewPanel({ client, sessionId, locale }) {
590
+ const tabsId = (0, react.useId)();
591
+ const gate = (0, react.useRef)(createReviewGeneration());
592
+ const sessionRef = (0, react.useRef)(sessionId);
593
+ const workRef = (0, react.useRef)(null);
594
+ sessionRef.current = sessionId;
595
+ const [tab, setTab] = (0, react.useState)("lessons");
596
+ const [snapshot, setSnapshot] = (0, react.useState)();
597
+ const [busy, setBusy] = (0, react.useState)(false);
598
+ const [note, setNote] = (0, react.useState)("");
599
+ const [error, setError] = (0, react.useState)("");
600
+ const [selected, setSelected] = (0, react.useState)([]);
601
+ const busyRef = (0, react.useRef)(false);
602
+ busyRef.current = busy;
603
+ function rpc(endpoint, payload, signal) {
604
+ return client.connection.rpc.call(SELF_IMPROVEMENT_RPC_CHANNEL, endpoint, payload, signal);
605
+ }
606
+ async function call(endpoint, payload = {}) {
607
+ return unwrap(await rpc(endpoint, payload));
608
+ }
609
+ (0, react.useEffect)(() => {
610
+ const request = beginReviewRequest(gate.current, sessionId, workRef.current);
611
+ workRef.current = request.controller;
612
+ setError("");
613
+ setNote("");
614
+ loadReviewSnapshot({
615
+ rpc,
616
+ sessionId: request.sessionId,
617
+ token: request.token,
618
+ gate: gate.current,
619
+ signal: request.signal,
620
+ viewSessionId: () => sessionRef.current
621
+ }).then((next) => {
622
+ if (next === void 0) return;
623
+ setSnapshot(next);
624
+ }).catch((cause) => {
625
+ if (!reviewRequestStillCurrent({
626
+ token: request.token,
627
+ gate: gate.current,
628
+ signal: request.signal,
629
+ sessionId: request.sessionId,
630
+ viewSessionId: sessionRef.current
631
+ })) return;
632
+ setError(cause instanceof Error ? cause.message : locale === "en" ? "Unable to read self-improvement state." : "无法读取自我改进状态。");
633
+ });
634
+ return () => disposeReviewRequest(gate.current, workRef.current ?? request.controller);
635
+ }, [
636
+ client,
637
+ sessionId,
638
+ locale
639
+ ]);
640
+ useFeatureRefresh(client, sessionId, () => {
641
+ peekReviewSnapshot({
642
+ rpc,
643
+ sessionId: sessionRef.current,
644
+ token: gate.current.current(),
645
+ gate: gate.current,
646
+ viewSessionId: () => sessionRef.current,
647
+ busy: () => busyRef.current,
648
+ editing: () => false
649
+ }).then((next) => {
650
+ if (next) setSnapshot(next);
651
+ }).catch(() => {});
652
+ }, snapshot?.extracting === true, true);
653
+ async function action(run) {
654
+ const request = beginReviewRequest(gate.current, sessionId, workRef.current);
655
+ workRef.current = request.controller;
656
+ setBusy(true);
657
+ setNote("");
658
+ setError("");
659
+ const still = () => reviewRequestStillCurrent({
660
+ token: request.token,
661
+ gate: gate.current,
662
+ signal: request.signal,
663
+ sessionId: request.sessionId,
664
+ viewSessionId: sessionRef.current
665
+ });
666
+ try {
667
+ await run({
668
+ sessionId: request.sessionId,
669
+ token: request.token,
670
+ signal: request.signal
671
+ });
672
+ } catch (cause) {
673
+ if (!still()) return;
674
+ setError(cause instanceof Error ? cause.message : locale === "en" ? "Action failed." : "操作失败。");
675
+ const next = await loadReviewSnapshot({
676
+ rpc,
677
+ sessionId: request.sessionId,
678
+ token: request.token,
679
+ gate: gate.current,
680
+ signal: request.signal,
681
+ viewSessionId: () => sessionRef.current
682
+ }).catch(() => void 0);
683
+ if (next) setSnapshot(next);
684
+ } finally {
685
+ if (still()) setBusy(false);
686
+ }
687
+ }
688
+ const data = snapshot ?? emptySnapshot();
689
+ const visibleLessons = data.lessons;
690
+ const body = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
691
+ error ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
692
+ role: "alert",
693
+ className: "si-error",
694
+ children: error
695
+ }) : null,
696
+ note ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
697
+ role: "status",
698
+ children: note
699
+ }) : null,
700
+ data.storageFailed ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
701
+ role: "alert",
702
+ children: locale === "en" ? "Save failed; previous state was kept." : "保存失败,已保留上一次成功的状态。"
703
+ }) : null,
704
+ data.memoryAvailable ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
705
+ role: "alert",
706
+ className: "si-error",
707
+ children: memoryUnavailableCopy(locale)
708
+ }),
709
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
710
+ className: "si-tabs",
711
+ role: "tablist",
712
+ "aria-label": locale === "en" ? "Self-improvement" : "自我改进",
713
+ onKeyDown: (event) => {
714
+ if (![
715
+ "ArrowLeft",
716
+ "ArrowRight",
717
+ "Home",
718
+ "End"
719
+ ].includes(event.key)) return;
720
+ const buttons = [...event.currentTarget.querySelectorAll("[role=\"tab\"]")];
721
+ const index = buttons.indexOf(event.target);
722
+ if (index < 0) return;
723
+ event.preventDefault();
724
+ const next = event.key === "Home" ? 0 : event.key === "End" ? buttons.length - 1 : (index + (event.key === "ArrowRight" ? 1 : -1) + buttons.length) % buttons.length;
725
+ buttons[next]?.focus();
726
+ buttons[next]?.click();
727
+ },
728
+ children: [["lessons", locale === "en" ? "Lessons" : "教训"], ["skills", locale === "en" ? "Skills" : "技能草稿"]].map(([key, label]) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
729
+ type: "button",
730
+ role: "tab",
731
+ id: `${tabsId}-${key}-tab`,
732
+ "aria-controls": `${tabsId}-${key}-panel`,
733
+ "aria-selected": tab === key,
734
+ tabIndex: tab === key ? 0 : -1,
735
+ onClick: () => setTab(key),
736
+ children: label
737
+ }, key))
738
+ }),
739
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
740
+ role: "tabpanel",
741
+ id: `${tabsId}-lessons-panel`,
742
+ "aria-labelledby": `${tabsId}-lessons-tab`,
743
+ hidden: tab !== "lessons",
744
+ tabIndex: 0,
745
+ children: [
746
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
747
+ className: "si-meta",
748
+ children: locale === "en" ? "Extracted lessons take effect automatically and join prompts; revoke any time to retire one." : "摘录的教训自动生效并进入提示,可随时撤回。"
749
+ }),
750
+ sessionId ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
751
+ type: "button",
752
+ disabled: busy || !data.memoryAvailable,
753
+ onClick: () => void action(async (ctx) => {
754
+ if (!reviewRequestStillCurrent({
755
+ token: ctx.token,
756
+ gate: gate.current,
757
+ signal: ctx.signal,
758
+ sessionId: ctx.sessionId,
759
+ viewSessionId: sessionRef.current
760
+ })) return;
761
+ await call("extract", { sessionId: ctx.sessionId });
762
+ const next = await loadReviewSnapshot({
763
+ rpc,
764
+ sessionId: ctx.sessionId,
765
+ token: ctx.token,
766
+ gate: gate.current,
767
+ signal: ctx.signal,
768
+ viewSessionId: () => sessionRef.current
769
+ });
770
+ if (!next) return;
771
+ setSnapshot(next);
772
+ setNote(locale === "en" ? "Extracted from this session when evidence was sufficient." : "已按明确依据尝试摘录。");
773
+ }),
774
+ children: locale === "en" ? "Extract from this session" : "从本会话摘录"
775
+ }) : null,
776
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LessonList, {
777
+ lessons: visibleLessons,
778
+ locale,
779
+ busy: busy || !data.memoryAvailable,
780
+ projectId: data.projectId,
781
+ onPromote: (record) => void action(async (ctx) => {
782
+ await call("accept", {
783
+ id: record.id,
784
+ expectedRevision: record.revision,
785
+ scope: "global",
786
+ sessionId: ctx.sessionId
787
+ });
788
+ const next = await loadReviewSnapshot({
789
+ rpc,
790
+ sessionId: ctx.sessionId,
791
+ token: ctx.token,
792
+ gate: gate.current,
793
+ signal: ctx.signal,
794
+ viewSessionId: () => sessionRef.current
795
+ });
796
+ if (next) setSnapshot(next);
797
+ }),
798
+ onReject: (record) => void action(async (ctx) => {
799
+ await call("reject", {
800
+ id: record.id,
801
+ expectedRevision: record.revision,
802
+ sessionId: ctx.sessionId
803
+ });
804
+ const next = await loadReviewSnapshot({
805
+ rpc,
806
+ sessionId: ctx.sessionId,
807
+ token: ctx.token,
808
+ gate: gate.current,
809
+ signal: ctx.signal,
810
+ viewSessionId: () => sessionRef.current
811
+ });
812
+ if (next) setSnapshot(next);
813
+ }),
814
+ onRevoke: (record) => void action(async (ctx) => {
815
+ await call("revoke", {
816
+ id: record.id,
817
+ expectedRevision: record.revision,
818
+ sessionId: ctx.sessionId
819
+ });
820
+ const next = await loadReviewSnapshot({
821
+ rpc,
822
+ sessionId: ctx.sessionId,
823
+ token: ctx.token,
824
+ gate: gate.current,
825
+ signal: ctx.signal,
826
+ viewSessionId: () => sessionRef.current
827
+ });
828
+ if (next) setSnapshot(next);
829
+ })
830
+ })
831
+ ]
832
+ }),
833
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
834
+ role: "tabpanel",
835
+ id: `${tabsId}-skills-panel`,
836
+ "aria-labelledby": `${tabsId}-skills-tab`,
837
+ hidden: tab !== "skills",
838
+ tabIndex: 0,
839
+ children: skillManagement()
840
+ })
841
+ ] });
842
+ function skillManagement() {
843
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
844
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("fieldset", {
845
+ className: "si-select",
846
+ disabled: busy || !data.memoryAvailable,
847
+ children: [
848
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("legend", { children: locale === "en" ? "Active lessons for a skill draft" : "从已生效的教训生成草稿" }),
849
+ data.lessons.filter((record) => record.status === "active").map((record) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
850
+ type: "checkbox",
851
+ checked: selected.includes(record.id),
852
+ onChange: (event) => setSelected((current) => event.target.checked ? [...current, record.id] : current.filter((id) => id !== record.id))
853
+ }), record.title] }, record.id)),
854
+ data.lessons.some((record) => record.status === "active") ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
855
+ className: "si-meta",
856
+ children: locale === "en" ? "No active lessons yet." : "还没有已生效的教训。"
857
+ })
858
+ ]
859
+ }),
860
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
861
+ type: "button",
862
+ disabled: busy || selected.length === 0 || !data.memoryAvailable,
863
+ onClick: () => void action(async (ctx) => {
864
+ await call("skill.preview", {
865
+ lessonIds: selected,
866
+ sessionId: ctx.sessionId
867
+ });
868
+ const next = await loadReviewSnapshot({
869
+ rpc,
870
+ sessionId: ctx.sessionId,
871
+ token: ctx.token,
872
+ gate: gate.current,
873
+ signal: ctx.signal,
874
+ viewSessionId: () => sessionRef.current
875
+ });
876
+ if (!next) return;
877
+ setSnapshot(next);
878
+ setTab("skills");
879
+ }),
880
+ children: locale === "en" ? "Preview skill Markdown" : "预览技能 Markdown"
881
+ }),
882
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SkillList, {
883
+ skills: data.skills,
884
+ locale,
885
+ busy,
886
+ onAccept: (record) => void action(async (ctx) => {
887
+ await call("skill.accept", {
888
+ id: record.id,
889
+ expectedRevision: record.revision,
890
+ sessionId: ctx.sessionId
891
+ });
892
+ const next = await loadReviewSnapshot({
893
+ rpc,
894
+ sessionId: ctx.sessionId,
895
+ token: ctx.token,
896
+ gate: gate.current,
897
+ signal: ctx.signal,
898
+ viewSessionId: () => sessionRef.current
899
+ });
900
+ if (next) setSnapshot(next);
901
+ }),
902
+ onReject: (record) => void action(async (ctx) => {
903
+ await call("skill.reject", {
904
+ id: record.id,
905
+ expectedRevision: record.revision,
906
+ sessionId: ctx.sessionId
907
+ });
908
+ const next = await loadReviewSnapshot({
909
+ rpc,
910
+ sessionId: ctx.sessionId,
911
+ token: ctx.token,
912
+ gate: gate.current,
913
+ signal: ctx.signal,
914
+ viewSessionId: () => sessionRef.current
915
+ });
916
+ if (next) setSnapshot(next);
917
+ }),
918
+ onRevoke: (record) => void action(async (ctx) => {
919
+ await call("skill.revoke", {
920
+ id: record.id,
921
+ expectedRevision: record.revision,
922
+ sessionId: ctx.sessionId
923
+ });
924
+ const next = await loadReviewSnapshot({
925
+ rpc,
926
+ sessionId: ctx.sessionId,
927
+ token: ctx.token,
928
+ gate: gate.current,
929
+ signal: ctx.signal,
930
+ viewSessionId: () => sessionRef.current
931
+ });
932
+ if (next) setSnapshot(next);
933
+ }),
934
+ onExport: (record) => void action(async (ctx) => {
935
+ if (await exportSkillIfCurrent({
936
+ rpc,
937
+ sessionId: ctx.sessionId,
938
+ token: ctx.token,
939
+ gate: gate.current,
940
+ signal: ctx.signal,
941
+ viewSessionId: () => sessionRef.current,
942
+ record
943
+ }) !== "recorded") return;
944
+ const next = await loadReviewSnapshot({
945
+ rpc,
946
+ sessionId: ctx.sessionId,
947
+ token: ctx.token,
948
+ gate: gate.current,
949
+ signal: ctx.signal,
950
+ viewSessionId: () => sessionRef.current
951
+ });
952
+ if (!next) return;
953
+ setSnapshot(next);
954
+ setNote(locale === "en" ? "Browser download started. Destination is chosen in the save dialog." : "已开始浏览器下载,保存位置由系统对话框决定。");
955
+ }),
956
+ onUnexport: (record) => void action(async (ctx) => {
957
+ await call("skill.unexport", {
958
+ id: record.id,
959
+ expectedRevision: record.revision,
960
+ sessionId: ctx.sessionId
961
+ });
962
+ const next = await loadReviewSnapshot({
963
+ rpc,
964
+ sessionId: ctx.sessionId,
965
+ token: ctx.token,
966
+ gate: gate.current,
967
+ signal: ctx.signal,
968
+ viewSessionId: () => sessionRef.current
969
+ });
970
+ if (!next) return;
971
+ setSnapshot(next);
972
+ setNote(exportRevocationCopy(locale));
973
+ })
974
+ })
975
+ ] });
976
+ }
977
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
978
+ className: "si-settings",
979
+ "data-testid": "self-improvement-settings",
980
+ "data-session": sessionId || void 0,
981
+ children: [sessionId ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
982
+ className: "si-meta",
983
+ children: locale === "en" ? "Select a session to view lessons for the current project." : "选择一个会话后可查看当前项目的教训。"
984
+ }), body]
985
+ });
986
+ }
987
+ const styles = `
988
+ .si-settings{max-width:760px;color:inherit;font:400 var(--font-size-2,14px)/1.5 var(--default-font-family,system-ui,sans-serif)}
989
+ .si-settings{display:grid;gap:16px}
990
+ .si-settings p{margin:0;line-height:1.5}
991
+ .si-meta,.si-empty{font-size:var(--font-size-1,13px);color:var(--gray-11,inherit)}
992
+ .si-error{color:var(--red-11,#b42318)}
993
+ .si-card{display:grid;gap:8px;padding:12px 14px;border:1px solid var(--gray-6,color-mix(in srgb,currentColor 15%,transparent));border-radius:12px}
994
+ .si-card h3{margin:0;font-size:var(--font-size-3,16px);font-weight:600}
995
+ .si-list{margin:0;padding:0;list-style:none}
996
+ .si-evidence{margin:0;padding-left:1.2em;font-size:var(--font-size-1,13px)}
997
+ .si-actions{display:flex;flex-wrap:wrap;gap:8px}
998
+ .si-settings button:not([role="tab"]){min-height:34px;padding:6px 12px;border:1px solid color-mix(in srgb,currentColor 25%,transparent);border-radius:8px;background:transparent;color:inherit;cursor:pointer;font:inherit;justify-self:start;transition:background-color 150ms ease,color 150ms ease,border-color 150ms ease,box-shadow 150ms ease,transform 150ms ease}
999
+ .si-settings button:not([role="tab"]):hover:not(:disabled){background:var(--gray-3,color-mix(in srgb,currentColor 6%,transparent));border-color:color-mix(in srgb,currentColor 35%,transparent)}
1000
+ .si-settings button:not([role="tab"]):active:not(:disabled){transform:scale(.97)}
1001
+ .si-danger:hover:not(:disabled){border-color:var(--red-11,#b42318);color:var(--red-11,#b42318);background:color-mix(in srgb,var(--red-11,#b42318) 8%,transparent)}
1002
+ .si-settings button:disabled{opacity:.45;cursor:not-allowed}
1003
+ .si-tabs{display:flex;gap:20px;border-bottom:1px solid var(--gray-6,color-mix(in srgb,currentColor 15%,transparent))}
1004
+ .si-tabs button[role="tab"]{padding:8px 0;border:0;border-bottom:2px solid transparent;border-radius:0;background:transparent;color:var(--gray-11,inherit);cursor:pointer;font:inherit;transition:color 150ms ease,border-color 150ms ease}
1005
+ .si-tabs button[role="tab"]:hover{color:inherit}
1006
+ .si-tabs button[aria-selected="true"]{border-bottom-color:var(--accent-9,#3b82f6);color:var(--accent-11,inherit);font-weight:600}
1007
+ .si-settings [role="tabpanel"]{border-radius:12px}
1008
+ .si-settings :focus-visible{outline:2px solid var(--accent-9,currentColor);outline-offset:3px}
1009
+ .si-preview{margin:0;padding:8px 10px;border-radius:8px;background:var(--gray-2,color-mix(in srgb,currentColor 4%,transparent));white-space:pre-wrap;overflow:auto;max-height:240px;font:400 var(--font-size-1,13px)/1.45 var(--code-font-family,ui-monospace,monospace)}
1010
+ .si-select{margin:0;border:1px solid var(--gray-6,color-mix(in srgb,currentColor 15%,transparent));border-radius:10px;padding:8px 12px;display:grid;gap:6px}
1011
+ .si-select label{display:flex;gap:8px;align-items:flex-start}
1012
+ @media(prefers-reduced-motion:reduce){.si-settings button{transition:none}}
1013
+ `;
1014
+ function reviewPanelKey(sessionId, locale) {
1015
+ return `${sessionId}:${locale}`;
1016
+ }
1017
+ function SelfImprovementSettings({ client, props }) {
1018
+ const seat = useNativeSeat(client, props);
1019
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReviewPanel, {
1020
+ client,
1021
+ sessionId: seat.sessionId,
1022
+ locale: seat.locale
1023
+ }, reviewPanelKey(seat.sessionId, seat.locale));
1024
+ }
1025
+ function apply(ctx) {
1026
+ const client = ctx;
1027
+ ctx.effect(() => {
1028
+ if (typeof document === "undefined") return () => {};
1029
+ const style = document.createElement("style");
1030
+ style.setAttribute("data-plugin", "@klarkxy/dsh-self-improvement");
1031
+ style.textContent = styles;
1032
+ document.head.appendChild(style);
1033
+ return () => style.remove();
1034
+ }, "self-improvement.styles");
1035
+ ctx.effect(() => client.slots.inject("settings.section", () => client.slots.register({
1036
+ name: "settings.section",
1037
+ id: "self-improvement",
1038
+ order: 85,
1039
+ label: "自我改进"
1040
+ }, (props) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SelfImprovementSettings, {
1041
+ client,
1042
+ props
1043
+ }))), "self-improvement.settings");
1044
+ }
1045
+ //#endregion
1046
+ exports.ReviewPanel = ReviewPanel;
1047
+ exports.SelfImprovementSettings = SelfImprovementSettings;
1048
+ exports.apply = apply;
1049
+ exports.beginReviewRequest = beginReviewRequest;
1050
+ exports.createReviewGeneration = createReviewGeneration;
1051
+ exports.disposeReviewRequest = disposeReviewRequest;
1052
+ exports.exportSkillIfCurrent = exportSkillIfCurrent;
1053
+ exports.inject = inject;
1054
+ exports.loadReviewSnapshot = loadReviewSnapshot;
1055
+ exports.memoryUnavailableCopy = memoryUnavailableCopy;
1056
+ exports.name = name;
1057
+ exports.parseSeatProps = parseSeatProps;
1058
+ exports.peekReviewSnapshot = peekReviewSnapshot;
1059
+ exports.reviewPanelKey = reviewPanelKey;
1060
+ exports.reviewRequestStillCurrent = reviewRequestStillCurrent;
1061
+ exports.shouldSkipReviewRefresh = shouldSkipReviewRefresh;
1062
+ exports.unwrap = unwrap;
1063
+
1064
+ //# sourceMappingURL=client.inner.cjs.map
1065
+ return module.exports;
1066
+ }
1067
+ });